Documentation Archive Developer
Search


Developer Release Notes
Cocoa Application Framework (macOS 10.12.2 and Earlier)

This document contains the AppKit release notes for macOS 10.12.2 and earlier. Please refer to the current release notes for AppKit before referring to this document, as the more recent changes in the current release could have obsoleted some of the items discussed here.

The notes below are split into the following sections:




Notes specific to macOS 10.12.2

Support for NSTouchBar

We introduced a version of macOS 10.12.1 with API to support the Touch Bar. There was also a version of macOS 10.12.1 that did not include support for the Touch Bar. In order to simplify the API story going forward, we have marked all NSTouchBar related API as available on 10.12.2 and later.

Please see the documentation for detailed information on how to use these classes, and see notes below for additional guidance and known issues.

Support for replacing the escape key in NSTouchBar

In MacOS 10.12.2 the NSTouchBar class has a new property – escapeKeyReplacementItemIdentifier. When non-nil the item with the specified identifier replaces the normal system provided escape key. This item should be provided by the delegate in the touchBar:makeItemForIdentifier: method, or located inside the NSTouchBar's templateItems set. For consistency with the rest of the system, the item should generally be a button, and should be used for canceling operations, or operations that can be undone.

Buttons in the esc key region will be automatically sized to the standard esc key width, and will only grow wider if their content requires it. In order to allow as much content as possible, they have modified metrics to reduce their inner padding. However, you should consider the space limitation when choosing localized strings in order to allow the button to stay at the standard width.

The escapeKeyReplacementItemIdentifier should be unique and not present in the normal defaultItemIdentifiers array.

If multiple NSTouchBar instances have replacement escape key items, the NSTouchBar provided closest to the first responder wins.

NSSliders in NSPopoverTouchBarItems

NSPopoverTouchBarItems that support press-and-hold and contain NSSliderTouchBarItems now have a one second delay before being dismissed after a press-and-hold gesture finishes. During that one second, interaction with the slider can be resumed and further delay the automatic dismissal of the popover.

Control appearance during NSTouchBar customization

Customization will now show the stateless appearance of NSTouchBarItem controls in both the on screen palette and the bar preview. This means that controls will not show their disabled, highlighted, or selection state while the bar is being customized.

NSCollectionViewFlowLayout fix

macOS 10.12 introduced an unintentional change in the way items are aligned in an incomplete (non-full) solitary row.  macOS 10.12.2 restores the alignment behavior from previous releases, where items in a single row are positioned the same as in the last row of a multi-row flow layout.

NSInspectorBar fix

32-bit apps running on 10.12.0 and 10.12.1 would crash after enabling NSTextView’s formatting bar (by setting "usesInspectorBar" to YES). This is fixed with 10.12.2.


Notes specific to macOS 10.12.1

Context Transition Animations in the Touch Bar

AppKit will animate changes to which NSTouchBarItems are presented to the user any time a change is made to an NSTouchBar or the responder chain changes.

In order to avoid unnecessary animation, AppKit will notice when items have the same identifier and frame and will not animate those changes. In order to achieve this result, use the same itemIdentifier between NSTouchBarItem instances that represent the same object to the user in different instances of NSTouchBar. If the responder chain changes such that NSTouchBar 'A' is being replaced by NSTouchBar 'B' and they both include a button with the title 'Cancel' the same itemIdentifier should be used for both items. AppKit will notice NSTouchBarItem instances that have the same itemIdentifier and the same frame and will not animate them even though the instances are changing.

It is important to note, however, that if the frame of the item being added is different from the frame of the item being removed, AppKit will still animate the change even if the itemIdentifiers are the same. If possible, avoid changes that would cause the frame of these items to change in between presentations.

NSTouchBar Support in Alerts

NSAlerts will automatically mirror buttons into the Touch Bar. The buttons presented in the bar will call -performClick: on the corresponding buttons in the NSAlert when tapped.

Custom windows presented as sheets or as modal windows to the user will need to add this behavior manually as AppKit will not automatically add these buttons to the bar.

Principal Items in NSTouchBar

The principal item of an NSTouchBar will try to occupy the same amount of space as the QuickType item. If a principal NSTouchBarItem can not occupy the width of QuickType, it will be sized as close to that width as possible.

Minimum and Maximum Size of NSTouchBarItems

AppKit will measure the minimum and maximum sizes of NSTouchBarItems at runtime. AppKit will cache these measured values and recalculate when necessary. Both the minimum and maximum sizes are measured at a priority of 200.

An NSTouchBarItem's view should use auto-layout when possible to express the sizes which the view is capable of occupying. Use constraints with priorities higher than 200 to express minimum and maximum thresholds. AppKit will notice if a constraint is changed and recalculate the minimum and maximum widths of the view.

When using intrinsicContentSize, call -invalidateIntrinsicContentSize when something changes that affects the intrinsicContentSize. Otherwise, AppKit will not notice the change and will not measure the new minimum and maximum sizes of the NSTouchBarItem's view.

In general, NSTouchBarItem's views should not have an opinion about their width outside of their minimum and maximum sizes. AppKit will decide how much space a given view should occupy within the minimum and maximum size of a view relative to what else is in the Touch Bar.

NSTouchBar and Right to Left support

NSTouchBar does not currently support right to left specific behaviors at the top level. This means that AppKit will not automatically flip NSTouchBarItems in a right to left localization.
Please do not manually reorder defaultItemIdentifiers as this will break user customized bars. Instead, try to encapsulate views that absolutely must flip inside of single views such as an NSStackView. NSView subclasses will continue to flip in right to left localizations when using auto-layout based on the NSUserInterfaceLayoutDirection. In general, anything beyond encapsulating views inside of a single NSView should be avoided as AppKit support may change in the future.



Segmented Control minimum size

Beginning with macOS 10.12.1, NSSegmentedControls will allow their titles to be easily compressed if they also have images.  In this case, the default compression resistance drops to 100, and a "minimum size" constraint is applied with a priority of 750 to prevent clipping of the images or bezel.  If you want your segmented control to be harder to compress, it will be necessary to set a compression resistance priority larger than this default.



Touch Events and Event Routing

The Touch Bar produces direct touch events that contain a set of NSTouches. These events are similar to the indirect touch events that are produced by Magic Trackpads, but there are some differences you should be aware of. For example, direct touch events are routed much like on iOS. Each Direct touch is routed to its hit tested view and may also be sent to gesture recognizers. See the section on NSTouch for more details.

Like indirect touches, each direct touch event and resulting NSTouch is an immutable snapshot of the event or touch at that instant. This is different from iOS where the same UITouch instance is reused for the duration of that touch.

Direct touch events are noted by the new event type, NSEventTypeDirectTouch. While there is a corresponding NSEventMaskDirectTouch, you cannot acquire direct touch events via -nextEventMatchingMask: or similar tracking methods. Direct Touches don’t flow through -sendEvent: either. Instead, direct touch events are routed upon receipt by the application. Important Note: This means that direct touch events are routed even when your app is in a tracking loop.

Direct touch events are coalesced. That is, all direct touch events in the event queue since the last touch event delivery are combined into a single event. The following function allows you to get the individual touches that make up the coalesced touch when needed.
  /* An array of auxiliary NSTouch’s for the touch events that did not get delivered for a given main touch.
This also includes an auxiliary version of the main touch itself. Only valid for NSEventTypeDirectTouch events.*/
public func coalescedTouches(for touch: NSTouch) -> [NSTouch]
NSView has been updated for direct touches as well. Notably, the acceptsTouchEvents property has been deprecated in favor of the new allowedTouchTypes property. The allowed touch types can be either empty, .indirect, .direct or both. For pre-10.12 built application, the default is empty. For applications built on 10.12 or later, the default is .direct. Your custom view can receive touch events by overriding the following responder functions:
  public func touchesBegan(with event: NSEvent)
public func touchesMoved(with event: NSEvent)
public func touchesEnded(with event: NSEvent)
public func touchesCancelled(with event: NSEvent)

NSTouch

Direct touches are exposed as the NSTouch object. New properties and functions have been added to handle the differences between a direct touch from the Touch Bar and and indirect touch from a trackpad. You can ask the touch for its type so you know which functions are available to you.
  public enum NSTouchType : Int {
case direct // A direct touch from a finger (on a screen)
case indirect // An indirect touch (not a screen)
}
  public var type: NSTouchType { get }
Direct touches do not have a normalizedPosition in the digitizer space. Instead their position is in view coordinates.
  public func location(in view: NSView?) -> NSPoint
public func previousLocation(in view: NSView?) -> NSPoint
AppKit will throw an exception if you attempt to acquire the wrong type of position for the type of touch.

As NSTouch objects are immutable, use the .identity property to track a specific touch throughout its life. Use the isEqual function to compare two touch identities.

Currently, the vertical position of all touches on the Touch Bar is generated from approximately the vertical center of the digitizer. As such, there is no vertical movement in touches in the current incarnation.

NSGestureRecognizer

Direct touch support has been added to most AppKit gesture recognizers. The complete list is: NSClickGestureRecognizer, NSPressGestureRecognizer, NSPanGestureRecognizer and NSMagnificationGestureRecognizer. By default, gesture recognizers do not receive touches. You can enable this by setting the new allowedTouchTypes property to .direct. Note: at this time, gesture recognizers still do not receive indirect touches. In addition, with the exception of NSMagnificationGestureRecognizer, you must set the numberOfTouchesRequired to a non zero value.

NSGesture recognizer subclassers can receive touch events by overriding the following responder functions:
  public func touchesBegan(with event: NSEvent)
public func touchesMoved(with event: NSEvent)
public func touchesEnded(with event: NSEvent)
public func touchesCancelled(with event: NSEvent)
Direct touches do not send shouldAttemptToRecognizeWithEvent messages to their NSGestureRecognizerDelegate. Instead the iOS approach is used where the delegate is sent a message for each touch.
  optional public func gestureRecognizer(_ gestureRecognizer: NSGestureRecognizer, shouldReceive touch: NSTouch) -> Bool

NSScrubber

macOS 10.12.1 introduces NSScrubber, a new AppKit control which arranges a finite collection of selectable content within the Touch Bar. It offers a variety of interaction modes and a flexible layout system. See the documentation for NSScrubber, NSScrubberLayout, and NSScrubberItemView for detailed information on how to build a scrubber control.

In 10.12.1, there is a known issue which prevents a NSScrubber configured for free scrolling and continuous selection from working properly with a layout that is dependent on the selected item.



Sharing Service Picker for NSTouchBar

NSSharingServicePickerTouchBarItem allows one to easily add a popover bar that utilizes the sharing service. It works similar to the NSSharingServicePicker, and the delegate derives from NSSharingServicePickerDelegate and adds the ability to dynamically provide the items to share.

NSSharingServicePickerTouchBarItem can not have the delegate be set to itself; this will cause an infinite loop.



Popover chevrons

The popover chevron is automatically displayed when the popoverTouchBar and pressAndHoldTouchBar properties refer to the same NSTouchBar instance. When the bars are different (including when the pressAndHoldTouchBar is nil) the chevron will not be displayed. Please note also that the chevron can not be automatically displayed when the item’s collapsedRepresentation has been replaced.

Popover nesting

Popovers are not nestable. Behavior is undefined if a popover item is used inside another popover item’s popoverTouchBar or pressAndHoldTouchBar.

A note on first responders

As the set of displayable bars is built from the responder chain, it is important that your responder chain matches what you expect. A common hiccup for views and view controllers is that they or a previous responder needs to be the first responder of a window. This might require over-riding the -acceptsFirstResponder method in a responder subclass.



NSTouchBar and Text

The NSTouchBar feature surrounding the text editing functionalities is a core part of the user experience offered by the new hardware. NSTextView participates in the NSTouchBar facility out of the box and provides text editing and formatting functionalities transparently without requiring adoptions from applications. NSCandidateListTouchBarItem, a concrete NSTouchBarItem subclass, can be easily configured to show the natural language candidate list appropriate for the current user document by working with NSSpellChecker and the text input system. NSTouchBar supports a text-related item identifier, NSTouchBarItemIdentifierCharacterPicker, and returns an NSPopoverTouchBarItem configured to show the system character picker from -itemForIdentifier:.


NSTextView Support

NSTextView should be able to present its NSTouchBar items out of the box without relying on any external controller from applications. For that, the view object implements -makeTouchBar configuring the item identifiers based on its property settings such as -isRichText. Also, NSTextView conforms to the NSTouchBarDelegate protocol and makes itself the delegate inside -makeTouchBar. This ensures its built-in items are properly associated with the bar through -touchBar:makeItemForIdentifier:. The method recognizes item identifiers for text color, text style (B/I/U), text alignment, text list, candidate list, and a group item preconfigured to contain the items above. The identifiers are NSTouchBarItemIdentifierTextColorPicker, NSTouchBarItemIdentifierTextStyle, NSTouchBarItemIdentifierTextAlignment, NSTouchBarItemIdentifierTextList, NSTouchBarItemIdentifierCandidateList, and NSTouchBarItemIdentifierTextFormat.

There are new APIs for controlling the items displayed by NSTextView. A new property, -allowsCharacterPickerTouchBarItem, controls whether to include the system character picker with the text view. The property is also available for NSTextField and its subclasses. When properties affecting the item identifiers such as -isRichText, -updateTouchBarItemIdentifiers gets messaged. NSTextViewDelegate can get notified via -textView:shouldUpdateTouchBarItemIdentifiers:.

Whenever the states for text NSTouchBar items need updating, -[NSTextView updateTextTouchBarItems] gets messaged.



NSSpellChecker Support for NSTouchBar Candidate Generation

NSCandidateListTouchBarItem is a special purpose NSTouchBarItem subclass that provides the candidate list functionality. It is used by default by NSTextView to show a natural language candidate list appropriate for the current user document by working with NSSpellChecker and the text input system. Other non-NSTextView clients may need their own access to candidate generation to obtain the same sort of candidates for use with NSCandidateListTouchBarItem, and NSSpellChecker provides facilities for that.

Candidate Generation

NSCandidateListTouchBarItem can be easily configured to work with NSSpellChecker and the text input system to display the candidate list appropriate for the user document content. Also, it can be configured to show arbitrary custom contents for applications. With the default configuration, the item is associated with NSTouchBarItemIdentifierCandidateList.

Showing candidates from NSSpellChecker
    The system candidate list based on the current selection inside the user document can be queried via the asynchronous method -[NSSpellChecker requestCandidatesForSelectedRange:inString:types:options:inSpellDocumentWithTag:completionHandler:]. The client passes in a string that should contain at least a paragraph’s worth of context around the point of interest (typically the insertion point). The selectedRange argument gives an indication of where the completion is occurring, and it should represent the portion of the string being checked that is selected, or be NSMakeRange(insertionPointIndex, 0) if there is an insertion point within or adjacent to the string being checked, or be NSMakeRange(NSNotFound, 0) if the selection is entirely outside of the string being checked.
    As with other NSSpellChecker asynchronous methods, the return value from this method is a sequence number that can be compared against the number passed to the completion block, for example to protect against the possibility of the text having changed in the interim. When the candidates become available, the completion block is called with an array of NSTextCheckingResult objects, specifying the range to be replaced, the replacement string, and the type of replacement. This call may be made on an arbitrary queue, so if clients need to operate on the candidates on the main queue they will need to arrange to send them there.

Showing candidates from the text input system
    The candidates from the text input system can be automatically displayed by configuring the candidate list item properly. The allowsTextInputContextCandidates property should be YES, and the client property should point to the target view conforming to the TextInputClient protocol. The view should return the candidate list item from -candidateListTouchBarItem.

Showing custom candidates
    With -setCandidates:forSelectedRange:inString:, applications can show arbitrary candidate such as contacts, e-mail addresses, telephone numbers, etc. With the configuration, the delegate property should contain an object conforming to NSCandidateListTouchBarItemDelegate for handling the touch on the Touch Bar.


NSTextView Candidate List Support

NSTextView supports NSCandidateListTouchBarItem and can manage the candidate list displaying the candidates from NSSpellChecker and the text input system. Also, NSTextViewDelegate now has additional methods for managing the candidate list item contents.

The automaticTextCompletionEnabled property controls whether to include the candidate list item in its NSTouchBar. NSTextField also has the corresponding property for controlling the behavior.

Two NSTextViewDelegate methods: -textView:candidatesForSelectedRange: and -textView:shouldSelectCandidateAtIndex:, can be used for managing custom candidates for the text view.

Related Methods

There is also an NSSpellChecker method, -deletesAutospaceBetweenString:andString:language:, for clients to use to after a candidate has been accepted, to determine whether or not to delete the trailing space after a candidate when the user subsequently types certain punctuation (such as periods and commas).

In addition, there is an NSSpellChecker method, +isAutomaticTextCompletionEnabled, to allow clients to find out the state of the user’s global preference for showing or not showing candidates, and a notification when this preference changes, NSSpellCheckerDidChangeAutomaticTextCompletionNotification.

Finally, one of the new keys introduced in 10.12 for clients to use with existing NSSpellChecker text checking methods, NSTextCheckingSelectedRangeKey, is needed in order to maintain consistency of results between these methods and the new candidate generation method. Clients should use this key in the options dictionary whenever they are calling NSSpellChecker methods like requestCheckingOfString:... or checkString:... that take an options dictionary. The value should be an NSValue created using -valueWithRange:, where the range should follow the same rules as the range passed in to requestCandidatesForSelectedRange:... Notice that the candidate generation method now has access to the selected range, so for consistency the text checking methods need access to it as well.

RTF Background Color Handling

In 10.12, 10.12.1, iOS 10, and 10.1, when a background color is set on a range of characters (using NSBackgroundColorAttributeName), and the resulting attributed string is saved as RTF and loaded back in, the characters following the range appear with a white background color, rather than no background color.  This is often not visible in cases where text is drawn on a white surface, but could be a problem otherwise.

This problem will be addressed in an upcoming release.



Notes specific to macOS 10.12

Some of the major topics covered in this section:



Overall API Updates

This release brings many API refinements, taking advantage of new API features in Objective-C and enabling APIs to come across more naturally in Swift.

Some of the key API update areas include:
- Adoption of Swift 3 API design guidelines, which has a large impact on the APIs as they appear in Swift.
- Adoption of Foundation Value Types, where appropriate in APIs. For instance NSData and NSURL in API now appear as Data and URL in Swift.  (Note that prefix dropping is a Foundation-only change and does not apply to other frameworks.)
- Updated names of enumerations to improve consistency and exposure in Swift.




NSCollectionView: Collapsable Sections

Finder’s icon view offers users the ability to collapse any section (each grouping by kind in “Arrange by: Kind” mode, for example) into a single horizontally scrollable row, via a “Show Less” button in the section’s header. A section will sometimes start out in this collapsed state, with the button (now titled “Show All”) toggling the section back into a normal flow layout. You can now easily offer the same capability to users of your NSCollectionViews.

To enable this feature:

1. Make your header view conform to the new NSCollectionViewSectionHeaderView protocol. This protocol provides an optional "sectionCollapseButton” property that we’ll use the help the CollectionView find the button.

2. Add an NSButton as a subview or descendant of your section header view. (If you’re using .xib files, you can do this in the interface editor.)

3. Set the button’s image or title to something general that indicates a toggle action — or, if desired, to indicate an initially uncollapsed state. (e.g. You’re likely to want it to read “Show Less”, or similar.)

4. Set up Auto Layout constraints to position your button as desired within the header view.

5. Wire the header view’s “sectionCollapseButton” outlet to your button.

6. Wire your button’s action to send -toggleSectionCollapse: to the First Responder. (Alternatively, you can use another action of your own, and have its implementation use either -toggleSectionCollapse: or the programmatic collapse/expand API described below to change the section’s state as desired.)

When the user clicks the button, -toggleSectionCollapse: should get routed to the NSCollectionView, which identifies the section based on the enclosing header view instance, and toggles the section’s collapsed state.

As in Finder’s icon view, the button is automatically shown when applicable, and hidden when not. If you want to change the title of the button to reflect the current collapsed/uncollapsed state, you can do so by overriding the -toggleSectionCollapse: action method on NSCollectionView to update the button’s title, after calling up to super. For example:
// Override -toggleSectionCollapse: to update the button's title.
- (void)toggleSectionCollapse:(id)sender { // "sender" is the "Show Less" / "Show All" button.
    // Let NSCollectionView collapse or expand the corresponding section.
[super toggleSectionCollapse:sender];
    // Update the button's label to show the action it will now perform.
if ([sender isKindOfClass:[NSButton class]]) {
// We must have a Flow layout, to be able to collapse and expand sections.
NSCollectionViewFlowLayout *layout = (NSCollectionViewFlowLayout *)[self collectionViewLayout];
if ([layout isKindOfClass:[NSCollectionViewFlowLayout class]]) {
            /* Find the containing header view, and from it the corresponding sectionIndex.
(The `sender` button is required to reside in a section Header view.) */
NSSet<NSIndexPath *> *headerIndexPaths = [self indexPathsForVisibleSupplementaryElementsOfKind:NSCollectionElementKindSectionHeader];
NSUInteger sectionIndex = NSNotFound;
for (NSIndexPath *headerIndexPath in headerIndexPaths) {
NSView *headerView = [self supplementaryViewForElementKind:NSCollectionElementKindSectionHeader atIndexPath:headerIndexPath];
if (headerView && [(NSView *)sender isDescendantOf:headerView]) {
sectionIndex = [headerIndexPath section];
break;
}
}
            if (sectionIndex != NSNotFound) {
NSString *newLabel;
if ([layout sectionAtIndexIsCollapsed:sectionIndex]) {
newLabel = [NSString stringWithFormat:@"Show All (%lu)", (unsigned long)[self numberOfItemsInSection:sectionIndex]];
} else {
newLabel = @"Show Less";
}
[(NSButton *)sender setTitle:newLabel];
}
}
}
}
This example method uses API that enables you to programmatically query and change the collapsed/expanded state of any section:
@interface NSCollectionViewFlowLayout
...
/* Returns YES if the specified section is currently collapsed; NO if not, or if there is no such section. Defaults to NO.
*/
- (BOOL)sectionAtIndexIsCollapsed:(NSUInteger)sectionIndex NS_AVAILABLE_MAC(10_12);
/* Collapses the specified section to a single row, if it is not already collapsed.
*/
- (void)collapseSectionAtIndex:(NSUInteger)sectionIndex NS_AVAILABLE_MAC(10_12);
/* Un-collapses the specified section, if it is currently collapsed.
*/
- (void)expandSectionAtIndex:(NSUInteger)sectionIndex NS_AVAILABLE_MAC(10_12);
...
@end

NSCollectionView: Floating Headers

Header and Footer views in a Flow layout can now be “floated”, using the same API provided by iOS’ UICollectionView.

Set these properties to YES to get headers that pin to the top of the visible area and footers that pin to the bottom while scrolling. These properties are archived with the layout's other persistent properties. Enabling this feature may affect the parenting of header and footer views.


@interface NSCollectionViewFlowLayout
...
@property BOOL sectionHeadersPinToVisibleBounds NS_AVAILABLE_MAC(10_12);
@property BOOL sectionFootersPinToVisibleBounds NS_AVAILABLE_MAC(10_12);
...
@end
When sectionHeadersPinToVisibleBounds is set to YES, the header view (if any) for the topmost visible section will stay pinned to the top of the scroll area in preference to being scrolled out of view. As the user scrolls down, the header stays pinned there until the next section’s header (or the top of the next section, if the next section has no header) pushes it out of the way.

The sectionFootersPinToVisibleBounds property behaves similarly, with pinning to the bottom of the scroll area provided instead.

NSCollectionView: Scrollable Background View

An NSCollectionView’s backgroundView can now be set to scroll together with the CollectionView’s content, instead of floating stationary behind the content. When backgroundViewScrollsWithContent is YES, the CollectionView's backgroundView (if any) will match the CollectionView's frame and scroll with the CollectionView's items and other content. When NO (the default, compatible with the behavior on OS X 10.11), the backgroundView is made to fill the CollectionView's visible area, and remains stationary when the CollectionView's content is scrolled. This property is archived with the CollectionView's other persistent properties.


@interface NSCollectionView
...
@property BOOL backgroundViewScrollsWithContent NS_AVAILABLE_MAC(10_12);
...
@end
Setting this property necessarily changes the way the backgroundView is parented. To float the backgroundView behind scrolling content, we make it a sibling of the CollectionView’s ClipView (as on 10.11). To have it scroll with the CollectionView’s content, we instead make the backgroundView a subview of the CollectionView.

The backgroundView property is meant to interoperate with backgroundColors (and now does so better, thanks to a fix in 10.12). If a CollectionView has both a backgroundView and backgroundColors, backgroundColors[0] will show through any areas not opaquely covered by the backgroundView. (backgroundColors beyond the first element are a legacy feature of NSCollectionView from OS X < 10.11. When using 10.11’s “new” NSCollectionView, only the first color is used.)

The backgroundView’s frame is set to match the CollectionView’s, and updated automatically to maintain that equality.

NSCollectionView: File Promise Drag Fix

On OS X 10.11, a dataSource-based NSCollectionView acting as the dragging source for a file promise drag would erroneously attempt to invoke the old -collectionView:namesOfPromisedFilesDroppedAtDestination:forDraggedItemsAtIndexes: delegate API method, instead of first checking for the newer -collectionView:namesOfPromisedFilesDroppedAtDestination:forDraggedItemsAtIndexPaths: API (and would raise an exception if the old-form delegate method wasn’t found). This has been fixed, so that NSCollectionView will first look for and attempt to invoke the new method. Failing presence of the new method, NSCollectionView will fall back to the old method, but only if it is a single-section CollectionView.

NSCollectionView: Delegate Message Send Fix

On 10.12, an NSCollectionView’s delegate now receives -collectionView:didEndDisplayingItem:forRepresentedObjectAtIndexPath: (and the corresponding items are placed in the CollectionView’s reuse queue) for all currently instantiated items when the CollectionView is removed from its window, and not just when the items are scrolled out of view or removed. This makes -collectionView:didEndDisplayingItem:forRepresentedObjectAtIndexPath: a more reliable cleanup opportunity for resources that may be associated with items. The same is true for -collectionView:didEndDisplayingSupplementaryView:forElementOfKind:atIndexPath: (which due to a bug was not sent at all on OS X 10.11).

On 10.12, -collectionView:willDisplaySupplementaryView:forElementKind:atIndexPath: is now sent for a supplementary or decoration view that is about to be displayed. Due to a bug, this delegate message was not sent on OS X 10.11.

NSCollectionViewGridLayout

NSCollectionViewGridLayout now implements -initWithCoder: and -encodeWithCoder: to persist and restore its properties as it should. It did not do so on OS X 10.11.


NSToolbar

NSToolbar's contextual menu will no longer show the "Hide Toolbar" item in applications linked on or after 10.12. Please be sure to include a menu item in your application's menu bar to toggle this behavior.

NSTabView - New since WWDC seed

NSTabView now has two new enums used to determine its style. NSTabPosition describes the position of the tabs and NSTabViewBorderType describes the border of the tab view. This is now the preferred method over using NSTabViewType.

Setting the tabPosition or tabViewBorderType will affect the NSTabViewType. Setting the tabViewType will also set the tabPosition and tabViewBorderType.
TabViewBorderType of anything other than NSTabViewBorderTypeBezel will only be respected if NSTabPosition is NSTabPositionNone as all other configurations are invalid. In an invalid configuration (i.e. a tabPosition of NSTabPositionLeft and a tabViewBorderType of NSTabViewBorderTypeLine) the tabViewBorderType will default to NSTabViewBorderTypeBezel.

NSSlider isVertical

NSSlider and NSSliderCell's `vertical` property is now readwrite and has changed its type from NSInteger to BOOL. In previous releases, NSSliderCell would try to automatically determine its orientation based on the aspect ratio of a received cell frame. This also led to -1 being returned from `isVertical` if it could not make a determination (e.g. the cell frame had a zero size), and could lead to the slider changing orientation when it was resized.

With 10.12, the vertical property is set at initialization time based on the aspect ratio of the frame parameter, and defaults to horizontal in ambiguous (equal width/height) cases; however it is recommended to explicitly set the vertical property or use the convenience constructors. To dynamically change the orientation of the slider, explicitly set the `vertical` property.


NSSplitView Delegate

For apps linked against the 10.12 SDK, NSSplitView's delegate property has zeroing `weak` memory semantics, compared to the previous `assign` memory semantics. However, if the object being set as the delegate doesn't support weak references, it will fallback to having assign semantics.

When linked against an older SDK, the delegate will continue to have `assign` semantics even when run on 10.12 or later.

It is important for apps that deploy to older OS X versions to still code against the `assign` semantics, and clear the delegate property when the delegate object is deallocated.


NSAlert Delegate

For apps linked against the 10.12 SDK, NSAlert's delegate property has zeroing `weak` memory semantics, compared to the previous `retain` memory semantics. However, if the object being set as the delegate doesn't support weak references, it will fallback to having assign semantics on 10.12.

When linked against an older SDK, the delegate will continue to have `retain` semantics even when run on 10.12 or later.

It is important for apps that deploy to older OS X versions to still consider the `retain` behavior and protect against retain cycles.


NSAlert Used Outside of Runloop

With 10.11 showing a modal NSAlert (or any other UI) outside of the main runloop will cause it to not disappear on modal session end. With 10.12, these alerts will be visually dismissed for apps linked against the 10.10 SDK or earlier. For newer apps, alerts should only be shown within the main run loop; or in cases where that is not possible, apps should make sure to flush the CATransaction after the modal run of the alert finishes (i.e. +[CATransaction flush]).



NSCursor

Prior to OS 10.12, -[NSCursor initWithImage:foregroundColorHint:backgroundColorHint:hotSpot:] would act as a designated initializer. The color hint parameters were unused and are now deprecated. For apps linked on or after OS 10.12, the color hint initializer calls into the new designated initializer, "-[NSCursor initWithImage:hotSpot:]". Apps which depend on which initializer is called should move to the new designated initializer.

NSCursor now better handles NSImage objects that contain vector representations and/or bitmap representations larger than @2x. It will now use the best available representation when the cursor is scaled via Accessibility preferences.




Layout Pass

In 10.12, the deferred view layout pass has been cleaned up, optimized and extended. This has resulted in several changes that developers should be mindful of when implementing view layout.

The deferred view layout pass represented by [NSView setNeedsLayout:] and [NSView layout] is now independent of autolayout and constraints. As a result, you can now implement custom layout mechanisms by overriding [NSView layout] without implicitly activating autolayout on the window. For example, if a view has child CALayers, it can now cleanly lay out those child layers in a [NSView layout] override and simply call [self setNeedsLayout:YES] whenever the child layout geometry needs to be updated in a deferred layout pass.

Previously, there were times where CoreAnimation would trigger [NSView layout] calls on parts of the view hierarchy out of band with the rest of the layout pass, resulting in inconsistent layout pass behavior or sometimes excessive layout calls on parts of the view hierarchy. The view layout pass is now driven entirely by AppKit. There could be cases where custom views were laying out child views or layers in a [view layout] override and were not setting view.needsLayout=YES appropriately, but the problem was masked by CoreAnimation. The solution in these cases is to ensure that view.needsLayout=YES is set whenever necessary. Note that layout for a view is now automatically invalidated when the view’s frame size changes, so view.needsLayout=YES should only be necessary on relevant state changes.

When overriding [NSView layout], AppKit no longer requires calling [super layout]. In particular, the view.needsLayout bit is now cleared automatically outside of the [view layout] call. This allows you to completely override [view layout] and block all of the default layout behavior if so desired. Also note that the bit is cleared before [view layout] is called, which means that if you dirty layout during your [view layout] override (either via calling [view setNeedsLayout:YES] directly or by modifying constraints), it will schedule a second layout pass.

Coordinated with a generic layout pass, AppKit now attempts to be smarter about when to actually engage an autolayout engine on an NSWindow. Specifically, the presence of an override to [NSView updateConstraints] now indicates to AppKit that the view in question, by default, uses constraints, and as such will activate autolayout in any NSWindow into which it is placed. If, however, you are writing a custom view type that supports but does not require constraints, then the correct solution, as before, is to override the class-level [NSView requiresConstraintBasedLayout] method and return NO.

As part of the layout pass optimization, AppKit is now more strict about certain requirements and limitations of the API. In particular:

- Be mindful of how layout is applied in a deferred manner, such that a view cannot rely on the frames of any subviews being current when its frame changes or during the view’s layout call (the ordering is not guaranteed). If you implement custom layout behaviors on top of deferred constraint-based layout and require the frames being current, the correct method is to call [self layoutSubtreeIfNeeded], which will perform the layout pass synchronously for just that subtree. Also note that using [self layoutSubtreeIfNeeded] is in general good practice if you are relying on frames of descendant views provided by other frameworks or libraries, since it can be difficult to determine whether any of those components use deferred layout or not, and the answer might change from release to release.

- AppKit is now more efficient about only calling -layout on views when actually necessary, which can reveal holes where code previously did not properly invalidate layout when necessary (the above CoreAnimation case being one of those instances). If you find -layout method not being called when expected on your view, make sure that the view is actually marked as needsLayout=YES.

- There are certain API calls that are specific to autoresizing masks or constraint-based layouts, and using one or the other, particularly in view hierarchies where both methods are used, can lead to unexpected results. Specifically, the resizeSubviewsWithOldSize/resizeWithOldSuperviewSize pair of API calls are specifically tied to autoresizing masks and whether a view has autoresizesSubviews set, and as a consequence those API calls can—and most likely will—be called before any constraint-based view layout is performed. The best layout-method-agnostic method of watching for size changes on a custom view class continues to be overriding the [NSView setFrameSize] call, and the best method for laying out children is to override [NSView layout], since it no longer automatically implies autolayout activation.

- The constraint solver works best when a set of layout constraints are activated once and left alone to re-evaluate as necessary during resize. However, if you must modify constraints as your view resizes, the best method continues to be overriding [NSView updateConstraints] and then setting self.needsUpdateConstraints=YES from within an [NSView setFrameSize] override. This method reduces the chance of a layout loop, makes layout dependencies easier to debug, and allow AppKit to better optimize the performance of the layout changes.

Improved debugging support for layout

AppKit now provides some additional support for debugging layout feedback loops. If you encounter layout passes that do not terminate naturally, you can run your application with the following argument: -NSViewLayoutFeedbackLoopDebuggingThreshold 100. The framework will then track dirty layout and attempt to identify cycles, logging information that may be useful in isolating the problem.

To assist debugging redundant view layout, there are now two user defaults. NSViewLayoutStrictMode, when enabled, will log the pointer of the view receiving redundant layout. This behavior can be modified to throw an exception by setting the NSViewLayoutStrictModeThrowsException user default to YES. NSViewLayoutStrictModeThrowsException has no effect when NSViewLayoutStrictMode is not set to YES.




Item Based Dragging File Promises

The Drag & Drop API has been modernized with two new classes: NSFilePromiseProvider and NSFilePromiseReceiver. These new objects:
    •    Support drag flocking
    •    UTI based
    •    Pasteboard Writer/Reader compliant
    •    File coordinated when possible
Also, NSFilePromiseProvider is compatible with drag destinations using the non-item based drag file promise API. Likewise, NSFilePromiseProvider is compatible with dragging sources using the non-item based drag file promise API.

Dragging File Promise Source - Changed since WWDC seed

Use the NSFilePromiseProvider class when creating file promises. Instantiate one NSFilePromiseProvider for each file promised. Before writing any NSFilePromiseProvider to the pasteboard, it must contain a file type being promised and an NSFilePromiseProviderDelegate. The file type must be a UTI that ultimately conforms to kUTTypeData or kUTTypeDirectory. The NSFilePromiseProviderDelegate will do the heavy lifting of writing the promised file to the destination directory. Optionally, you may attach a userInfo object of your choosing to the NSFilePromiseProvider. This is often useful to determine which promise is being referenced when promising multiple files and using the same NSFilePromiseProviderDelegate instance.

There are only three NSFilePromiseProviderDelegate methods you need to implement:
- (NSString *)filePromiseProvider:(NSFilePromiseProvider*)filePromiseProvider fileNameForType:(NSString *)fileType;
Discussion: This method is called when the drag destination “calls in” the file promise. At this point you should determine and return the final filename, which should be the base filename, not a full path. Note: The drag process is halted while waiting for this method to return. Taking too long in this method may result in the drag getting cancelled. Do not start writing the file yet.


- (void)filePromiseProvider:(NSFilePromiseProvider*)filePromiseProvider writePromiseToURL:(NSURL *)url
completionHandler:(void (^)(NSError *errorOrNil))completionHandler;
Discussion: Write the contents of this promise item to the provided URL and call completionHandler when done. It is important to call the completion handler as the file writing is wrapped with NSFileCoordinator. Likewise, be sure write your file to the supplied url parameter. This method is called after the drag completes. Note: This request shall occur on the NSOperationQueue supplied by -promiseOperationQueue.
- (NSOperationQueue *)promiseOperationQueueForFilePromiseProvider:(NSFilePromiseProvider*)filePromiseProvider;
Discussion: Return the operation queue that the write request should be issued from. If this method is not implemented, the mainOperationQueue is used. While optional, it is strongly recommended that you provide an operation queue other than the main operation queue to avoid blocking your main thread.

Dragging File Promise Destination

Use the NSFilePromiseReceiver object to receive file promises. Since NSFilePromiseReceiver implements the NSPasteboardReader protocol, you get all the file promises on the drag pasteboard like so:
    NSArray<NSFilePromiseReceiver*> filePromises = [pasteboard readObjectsForClasses:@[[NSFilePromiseReceiver class]] options:nil];
Likewise you can enumerate the draggingItems by
   [draggingInfo enumerateDraggingItemsWithOptions:0 forView:view classes:@[[NSFilePromiseReceiver class]]
searchOptions:@{} usingBlock:^(NSDraggingItem *draggingItem, NSInteger idx, BOOL *stop) {
NSFilePromiseReceiver *filePromiseReceiver = dragItem.item
}];
Compatibility note: A non-item based drag source (e.g. don’t use NSFilePromiseProvider) may promise multiple files on the same pasteboard item. To be compatible with these drag sources many NSFilePromiseReceiver methods return an array of values. Muti-file item based promises result in one NSFilePromiseReceiver per promised file.
+ (NSArray<NSString *> *)readableDraggedTypes;
Discussion: A view must register what types it accepts via -registerForDraggedTypes:. Use this class method to get the file promise drag types that NSFilePromiseReceiver can accept, in order to register a view to accept promised files. NSFilePromiseReceiver can accept file promises from both the item based NSFilePromiseProvider and the non-item based API. If you don’t register all these drag types you may fail to be notified about some file promise drags. Registration is simply: [view registerForDraggedTypes:[NSFilePromiseReceiver readableDraggedTypes]];
@property(copy, readonly) NSArray<NSString*> *fileTypes;
Discussion: Returns an array of UTIs for the filetypes promised. NSFilePromiseProvider promises 1 filetype per item. The count of fileTypes should tell you the number of promised files in this item, however, that is not guaranteed. Historically, some legacy file promisers only list each unique fileType once and write one or more files per type.
- (void)receivePromisedFilesAtDestination:(NSURL *)destinationDir options:(NSDictionary *)options
operationQueue:(NSOperationQueue *)operationQueue reader:(void(^)(NSURL *fileURL, NSError * __nullable errorOrNil))reader;
Discussion: This effectively calls in the promises. Therefore, only call once you are accepting the file promise. All file promisesReceiver's in a drag must specify the same destination location. The options dictionary is ignored for now. The reader block is called on the supplied operationQueue when the promised file is ready to be read. It is highly recommended that you specify an optation queue other than the main operation queue to avoid blocking the main thread waiting for the file promise to be written by the source (as this may be a long process). When the source is an NSFilePromiseProvider, the readerBlock call is wrapped in an NSFileCoordination read. Otherwise, a heuristic is used to determine when the promised file is ready to be read. Note: Writing of the promised file may fail. When that occurs, the readerBlock is still called with a non-nil error. There may be nothing at the fileURL, or it may be a partial / corrupt file.
@property(copy, readonly) NSArray<NSString*> *fileNames;
Discussion: Returns an array of the file names of the promised files that are being written to the destination location. This property returns an empty array until the file promise is called in via receivePromisedFilesAtDestination.



NSControl

Built-in NSControl subclasses now automatically mirror some directional properties (e.g. NSButton’s imagePosition) when unarchived from a Base-localized Interface Builder archive into a right-to-left user interface. This behavior is suppressed if the control is configured with “Mirror” set to “Never”.

The cases of the NSControlSize enumeration have been renamed to have a common prefix, per modern naming conventions. The existing names are now deprecated.

The -[NSControl sendAction:to:] method incorrectly declared its `theAction` parameter as non-nullable. It is now correctly marked as nullable.

NSButtonCell

The previously-unused gradientType property, and corresponding NSGradientType enumeration, are now deprecated.



NSButton

NSButton now has several new convenience constructors for creating system standard push buttons, checkboxes, and radio buttons:
    NSButton(title:target:action:)
    NSButton(image:target:action:)
    NSButton(title:image:target:action:)
    NSButton(checkboxWithTitle:target:action:)
    NSButton(radioButtonWithTitle:target:action:)
NSButton’s keyEquivalentModifierMask property is now declared with type NSEventModifierMask instead of NSUInteger.

NSTextField

NSTextField now has several new convenience constructors for creating non-wrapping labels, wrapping labels, attributed labels, and editable text fields:
    NSTextField(labelWithString:)
    NSTextField(wrappingLabelWithString:)
    NSTextField(labelWithAttributedString:)
    NSTextField(string:)
The -control:isValidObject: delegate method incorrectly declared the `object` parameters as nonnull. It is now correctly marked as nullable.

NSSegmentedControl

NSSegmentedControl has new convenience constructors for creating a segmented control given an array of labels or an array of images:
    NSSegmentedControl(labels:trackingMode:target:action:)
    NSSegmentedControl(images:trackingMode:target:action:)

NSSlider

NSSlider has new convenience constructors for creating horizontal linear sliders:
    NSSegmentedControl(target:action:)
    NSSegmentedControl(value:minValue:maxValue:target:action:)

NSImageView

NSImageView has a new convenience constructor for creating a non-editable image view with a given NSImage:
    NSImageView(image:)

NSButton - New since WWDC seed

NSButton provides a new property, imageHugsTitle, which affects how the button image is positioned when the button is made larger than its intrinsic content size. By default, the image is always positioned relative to the bezel edge, but with imageHugsTitle = YES, the image is always positioned adjacent to the title text.

NSButton now exposes an imageScaling property, available back to 10.5 and later. Accessing this property is preferred over accessing the NSButtonCell equivalent.

NSPopUpButton - New since WWDC seed

For applications linked against the macOS Sierra SDK and later, NSPopUpButton no longer reserves drawing space for arrows if arrowPosition is set to NSPopUpNoArrow.




New Layout Container: NSGridView

NSGridView is an auto layout container for arranging content views into a grid. At a high level it's similar to NSStackView, except it allows for alignment across both rows and columns. Like a spreadsheet, rows and columns can all be varying sizes, or dynamically hidden & shown. Individual cells may be merged to achieve a layout that crosses the basic grid boundaries. See NSGridView.h for the API and more information.

NSLayoutConstraint

NSLayoutConstraint now exposes properties for a firstAnchor and nullable secondAnchor. This is part of a longer-term move towards leveraging layout anchors more heavily in the API. Use of these is recommended over the existing item/attribute pairs, since some anchors cannot be represented that way. For this reason, NSLayoutConstraint's firstItem property is now nullable, and developers may begin to encounter valid constraints with nil items or NSLayoutAttributeNotAnAttribute.

NSViewNoInstrinsicMetric unavailable from Swift - New since WWDC seed

The NSViewNoInstrinsicMetric constant was replaced with the properly-spelled NSViewNoIntrinsicMetric in macOS 10.11, and is unavailable from swift. This can present a problem for swift developers that are using the 10.12 SDK, targeting macOS 10.10, and need to override intrinsicContentSize to not specify a size in one or both dimensions. In this case, it's acceptable to simply use -1.0 instead.



Accessibility

In NSAccessibilityConstants.h, we added the role constant “NSAccessibilityMenuBarItemRole” for items in the menubar.

In NSAccessibilityProtocols.h, the NSAccessibilityLayoutArea protocol now declares accessibilityFocusedUIElement as a read-only property rather than a method, so that it matches the NSAccessibility protocol. This allows Swift classes to implement the NSAccessibilityLayoutArea protocol by overriding the property.

In NSAccessibilityConstants.h, we added a new constant “NSAccessibilityRequiredAttribute” which indicates that a form field is required to have content for successful submission of the form. In NSAccessibilityProtocols.h, defined the corresponding protocol method for setting and getting the value of this attribute on an accessible object.

Menus

NSMenuItem’s keyEquivalentModifierMask property is now declared with type NSEventModifierMask instead of NSUInteger.

NSMenu and NSMenuItem now conform to the NSUserInterfaceItemIdentification protocol.

NSMenu and NSMenuItem now conform to the NSAccessibility and NSAccessibilityElement protocols. These classes now support the accessibility identifier and description that can be set in Interface Builder. You can also change the accessibility description in code with the -setAccessibilityLabel property setter.

NSMenu's delegate property is now declared "weak". The NSMenu implementation has actually stored a weak reference to the delegate (for zeroing-weak-compatible objects) since OS X v10.9, so this change is not a change in behavior but simply documents the current implementation.

Menus - New since WWDC seed

The popUpContextMenu and popUpMenuPositioningItem methods now align the menu at the popup location according to the user interface layout direction of the presenting view. If the view uses right-to-left layout, then the menu is right-aligned at the specified position; otherwise it is left-aligned.


NSTableView / NSOutlineView

NSTableView properly supports Right to Left Layout for applications that link on 10.12 and higher. Previously, the userInterfaceLayoutDirection was hardcoded to be NSUserInterfaceLayoutDirectionLeftToRight. NSTableView and NSOutlineView will now automatically flip the table column order for applications are right to left. This is only affects the visual representation of the table columns; the actual logical tableColumn array order is still maintained.

NSTableView (and NSOutlineView) now has a proper weak delegate and dataSource implementation. This means a developer is no longer required to clear them out to nil when the delegate (and/or dataSource) object is freed. This change applies to all applications on 10.12. Applications that target older releases should still reset the delegate to nil; doing so is harmless for 10.12 and higher. Note that the _delegate and _dataSource ivars in NSTableView have always been private, and should not be directly accessed. In 10.12, they are now opaque objects, and may not represent the real delegate or dataSource. Instead of directly using the ivars, one should use the property accessors.

NSOutlineView has a new property named stronglyReferencesItems to allow it to automatically retain the items returned to it when set to YES. The default value is YES for applications linked on 10.12 and higher, and NO otherwise. In general, this value should always be YES, but can be set back to NO for cases where the items would cause a retain cycle. This could happen if the item either directly or indirectly retained the outline view, which would cause it to never get released.

NSOutlineView will now reload the cell views associated with ‘item’ when [outlineView reloadItem:] is called. The method simply calls [outlineView reloadDataForRowIndexes:columnIndexes:] passing the particular row that is to be reloaded, and all the columns. For compatibility, this will only work for applications that link against the 10.12 SDK.

NSTableView will now reload "full width" cell views (meaning the column index for them is -1) when [tableView reloadDataForRowIndexes:columnIndexes:] is called, and the column index contains -1. For compatibility, this will only work for applications that link against the 10.12 SDK.

NSOutlineView - New since WWDC seed

NSOutlineView can now use isEqual: rather than pointer equality to compare items. NSOutlineView will use isEqual: rather than pointer equality if stronglyReferencesItems is set to YES.

Prior to 10.12, disabling mirroring in Interface Builder on an NSOutlineView would not work; this has been resolved. Applications that require an NSOutlineView to always be left-to-right (even in a right-to-left language) should explicitly set the userInterfaceLayoutDirection in code if they are targeting an OS prior to 10.12.


NSVisualEffectView

The class now has a new material for selection: NSVisualEffectMaterialSelection. In addition, a new property called emphasized can be used to indicate that the selection should draw in "first responder" status, or not.

NSWindow

NSTitlebarAccessoryViewController supports NSLayoutAttributeLeading and NSLayoutAttributeTrailing to specify an abstract position that automatically flips depending on the localized language. These only work for applications that link on 10.12 and later. For applications that do not link on 10.12, NSLayoutAttributeLeft will automatically flip to the Right when in a Right To Left language and when run on 10.12.

NSWindow's backgroundColor would be ignored if a custom appearance was set on the window, and the window's contentView had wantsLayer=YES. This has been fixed for all applications.

Replacing the contentViewController on an visible NSWindow would leave the firstResponder set to the window; this has now been fixed to automatically determine the correct first responder when the contentViewController is changed. Applications targeting prior OS releases should explicitly assign the firstResponder in the new contentViewController's viewWillAppear.



NSWindow Automatic Window Tabbing

Automatic Window Tabbing allows any application to easily (and automatically) adopt tabs. This feature stacks multiple windows together and presents a tab bar in the window title bar area to make it appear to the user as though there is one single window. In reality, only the selected tab's window is shown, and all the other windows are hidden directly using CoreGraphics. An application only has to order a window in, and it will automatically be tabbed with similar windows based on heuristics the user's preference for tabbing. Ordering a window out removes the tab. Windows that are not visible are ordered out with respect to CoreGraphics, but are still considered visible with respect to AppKit / NSWindow.

There is a new user System Preference under the Dock section to control tabbing. The behavior of this preference is described in General Flow below.

The NSWindow header has two new enumerations (NSWindowUserTabbingPreference, NSWindowTabbingMode) and several new properties. Please examine the header for some detailed comments on what the new methods are for.

API Adoption

    •    What should an application which works well with out-of-the-box window tabbing do? - In general, nothing has to be done. A non-NSDocument based application may wish to support the "+" button by implementing newWindowForTab: somewhere in the responder chain.
    •    What should an application which already has support for tabbing do? - The application should explicitly opt-out of automatic window tabbing by calling [NSWindow setAllowsAutomaticWindowTabbing:NO]. It should respect the userTabbingPreference and create tabs based on the General Flow described below.
    •    What should an application do to customize the standard tabbing behavior? - See the detailed Behavior section below for how the properties interact with each other.

General Flow

The behavior depends on the new system preference under the Dock section to allow tabbing: Always / In Full Screen Only [Default] / Manually. Holding down option, in general, will invert the standard behavior. For each option:

When In Full Screen Only [Default]:

* When in Full Screen all windows opened will prefer to tab, including menu items (Cmd-N, Open Recents, etc), the open panel, and opening documents from Finder.
* When in Full Screen Holding down option will prefer to window [in a new space] instead of a tab
* When on the Desktop things work exactly as they always have, with the additional ability to create tabs manually. See Manually.

When Always:

* When on the Desktop or in Full Screen opening similar windows should prefer to always tab, including menu items (Cmd-N, Open Recents, etc), the open panel, and opening documents from Finder.
* Holding down the option button will prefer to create a window instead of a tab.


When Manually:

* When on the Desktop or in Full Screen opening windows will prefer to just create a normal window.
* Holding down the option button will prefer to create a tab instead of a window.


Behavior

The userTabbingPreference is a representation of the system preference for tabbing. Applications that already explicitly adopt tabbing, including ones that do not use automatic window tabbing, should read the value of the userTabbingPreference before showing a window to determine if a regular show of a window should prefer to tab with other windows, or be shown in a new window.

[NSWindow allowsAutomaticWindowTabbing] is a way for an application to opt-out of automatic window tabbing. An application that opts out will not get the standard menu items that perform tabbing. The default value for allowsAutomaticWindowTabbing will be YES for all applications except for some that are specifically black-listed out. Those apps can explicitly adopt automatic window tabbing by setting the value of allowsAutomaticWindowTabbing to YES early in the application bring up (in applicationWillFinishLaunching).

A window’s tabbingMode always defaults to NSWindowTabbingModeAutomatic. When the tabbingMode is set to NSWindowTabbingModeAutomatic, and [NSWindow allowsAutomaticWindowTabbing] is YES, the system will automatically tab together similar windows based on tabbingIdentifier. Automatic window tabbing will attempt to tab together windows based on the userTabbingPreference, and how the window was created (based on the logic in “General Flow of Automatic Window Tabs”). When the tabbingMode is set to NSWindowTabbingModeAutomatic, and [NSWindow allowsAutomaticWindowTabbing] is NO, no automatic window tabbing will happen.

A window’s tabbingMode can explicitly be set to NSWindowTabbingModePreferred to allow the window to tab together with other similar windows based on the tabbingIdentifier. This can be set anytime an application wants a window to become in a tab. For instance, it can be set to NSWindowTabbingModePreferred for a window created by a Cmd-T shortcut to always create a window in a tab, regardless of any other system settings, and regardless of the userTabbingPreference. It is up to an application to properly respect the userTabbingPreference and set NSWindowTabbingModePreferred only at appropriate times.

A window’s tabbingMode can explicitly be set to NSWindowTabbingModeDisallowed to explicitly disallow window tabbing. It is up to an application to properly respect the userTabbingPreference and set NSWindowTabbingModePreferred only at appropriate times based on the logic in “General Flow of Automatic Window Tabs”.

A window’s tabbingMode is only checked when a window is about to be shown, and the tabbingMode should be updated before the window is ordered in.

New Button

The plus button will be shown if newWindowForTab: is implemented in the responder chain. NSDocumentController informally implements newWindowForTab:, but only returns YES from respondsToSelector: for this selector if the self.documentClassNames.count > 0 and if the app has a default new document type. In other words, it only responds to it if NSDocument has at least one registered document class name which can be edited.

NSWindow Actions

An application can utilize the standard window tabbing actions to select tabs, merge them into one window, etc: -selectNextTab:, -selectPreviousTab:, -moveTabToNewWindow:, -mergeAllWindows:, -toggleTabBar:.

By default, applications with automatic tabbing will get standard tab menu items added under the Window menu that are hooked up to these actions. However, an app may wish to add contextual menu options that perform the actions. Or, an application which opts-out of automatic tabbing (by setting NSApp.allowsAutomaticWindowTabbing=NO) may still wish to participate in tabs.

To validate the above actions, NSWindow will perform the validation inside its implementation of - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item;, but only if the selector matches one of the above items.



NSAnimation

Prior to macOS 10.12, NSAnimationEaseOut was reversed. It would perform an "ease in" animation beginning at the final value and ending at the initial value. For apps linked on or after macOS 10.12, NSAnimationEaseOut now describes a curve beginning at the initial value and ending at the final value, that slows down towards the end.

NSImage

NSImage now supports multiple representations to support different user interface layout directions.

This can be configured in Xcode for images loaded through asset catalogs. If you are building an image programmatically, note that NSImageRep gains a layoutDirection property. layoutDirection may take one of three values: NSImageLayoutDirectionUnspecified, NSImageLayoutDirectionLeftToRight, NSImageLayoutDirectionRightToLeft. NSImageLayoutDirectionUnspecified means that image rep is equally appropriate for left-to-right and right-to-left layout directions. It is the default value for new image reps.

When drawing an NSImage the correct layout direction is inferred based on the prevailing drawing conditions. This is the case for example inside a view's -drawRect: implementation. In some circumstances it is necessary to manually specify the desired layout direction. This can be accomplished by specifying the NSImageHintUserInterfaceLayoutDirection in the hints dictionary passed to NSImage's draw or rep selection methods.



NSColor

NSColorSpace now includes support for the “display P3” color space, which has standard DCI-P3 primaries, a D65 white point, and the same gamma curve as the sRGB IEC61966-2.1 color space. It is a canonicalization of the new iMac display profiles that is useful for tagging wide color gamut content.
+ (NSColorSpace *)displayP3ColorSpace;
We also have a corresponding convenience constructor in NSColor:
+ (NSColor *)colorWithDisplayP3Red:(CGFloat)r green:(CGFloat)g blue:(CGFloat)b alpha:(CGFloat)a;

NSColorSpace also exposes sRGB color spaces that enable specifying colors outside of the 0..1 range:
+ (NSColorSpace *)extendedSRGBColorSpace;
+ (NSColorSpace *)extendedGenericGamma22GrayColorSpace;
These provide extended versions of existing color spaces sRGBColorSpace and genericGamma22GrayColorSpace.


To provide consistency with UIColor, the behaviors of the following methods (all introduced in 10.9) have been modified to accept extended color component values. If red, green, blue, or saturation, brightness, or white values are outside of the 0..1 range, these will create colors in the extended sRGB or extendedGenericGamma22GrayColorSpace color spaces:
+ (NSColor *)colorWithWhite:(CGFloat)w alpha:(CGFloat)a;
+ (NSColor *)colorWithRed:(CGFloat)r green:(CGFloat)g blue:(CGFloat)b alpha:(CGFloat)a;
+ (NSColor *)colorWithHue:(CGFloat)h saturation:(CGFloat)s brightness:(CGFloat)b alpha:(CGFloat)a;

Finally, we have the following new API in NSColor to enable creation of RGB-based colors from HSB component values using an arbitrary color space. An exception will be raised if the color model of the provided color space is not RGB:
+ (NSColor *)colorWithColorSpace:(NSColorSpace *)space hue:(CGFloat)h saturation:(CGFloat)s brightness:(CGFloat)b alpha:(CGFloat)a;

NSWindow deep buffer support for wide color monitors

On monitors that support wide color, NSWindow automatically increases the default depth of associated backing stores and offscreen buffers. This can be overridden by setting NSWindow.dynamicDepthLimit = NO, and also setting NSWindow.depthLimit to the desired value. The supported depths are NSWindowDepthTwentyfourBitRGB, NSWindowDepthSixtyfourBitRGB, and NSWindowDepthOnehundredtwentyeightBitRGB. NSWindowDepthTwentyfourBitRGB is the historical default value, and the value used for monitors deemed insufficiently wide. NSWindowDepthSixtyfourBitRGB is the new default for wide monitors, like the P3 panels in the current iMacs. AppKit automatically adjusts the bitdepth of layer backing stores to match the window they are hosted in. This can be overridden on a layer by layer basis using CALayer.contentsFormat.

NSImage support for wide color image reps

NSImage will now use colorspace to disambiguate otherwise identical image reps. For example, on a system with Display P3 output colorspace NSImage will favor an NSBitmapImageRep whose colorspace is display P3, over an otherwise identical NSBitmapImageRep whose colorspace is sRGB.

The colorspace of an image rep can be set using the existing colorSpace property of NSBitmapImageRep, or by configuring the appropriate fields in the asset catalog inspector in Xcode.

Colors in RTF Files

Colors are now preserved in RTF files with a lot more fidelity, by recording the color space and writing count components with more precision. Among other things this enables deep colors to be saved in RTF files.

The extensions to the RTF spec that enable this will be published shortly.

NSDisplayGamut - New since WWDC seed

Some displays support a wide gamut colorSpace. By default, a window inherits its colorSpace from its display, so some windows support wide gamut colorSpaces as well. In 10.12, we've added a facility to check for a wide gamut screen or window so that, for example, the right image assets can be selected.

The NSDisplayGamut enumeration defines buckets for sRGB and p3.
typedef NS_ENUM(NSInteger, NSDisplayGamut) {
NSDisplayGamutSRGB = 1,
NSDisplayGamutP3
};
NSScreen and NSWindow have a method to check if the receiver is capable of representing the given display gamut.
- (BOOL)canRepresentDisplayGamut:(NSDisplayGamut)displayGamut;
Asset selection is one intended use for this API. If you have assets of varying gamut, start with the richest and ask your destination whether it can represent it. If you need to do asset selection without a known destination, use the first screen in NSScreen's screens array.
if ([window canRepresentDisplayGamut:NSDisplayGamutP3]) {
bestAsset = P3Asset;
} else {
bestAsset = sRBGAsset;
}

NSColorList - New since WWDC seed

NSColorList has a new API which enables saving color lists using the secure keyed archiving format. This format is preferred, since in addition to being more secure, it is more complete than the older unkeyed format, enabling archiving of colorspace-based colors. Files saved is this format can be read back as early as 10.11. The API is also available back to 10.11.

Like the existing writeToFile: method, specifying a nil destination causes the color list to be saved to the user's colorlists directory. This also adds the color list to availableColorLists, using the name of the color list.
- (BOOL)writeToURL:(nullable NSURL *)url error:(NSError **)errPtr;
At this point, use of the existing writeToFile: method is discouraged.

NSColorPanel writes color lists that are created or edited using the color palette picker with this modern format.



NSFont

The weight for +[NSFont boldSystemFontOfSize:] is changed to NSFontWeightBold to match the instance returned from +systemFontOfSize:weight: with NSFontWeightBold.


NSTextInputContext

The role of -invalidateCharacterCoordinates is clarified in the header comment. NSTextView is updated to adopt the new behavior.

NSTokenField

The menu indicator inside the token is now displayed on the left of title when -userInterfaceLayoutDirection is NSUserInterfaceLayoutDirectionRightToLeft.

NSLayoutManager

Just like on iOS, NSLayoutManager now renders NSLinkAttributeName with underlined blue color without any NSTextView attached on macOS for apps linked with 10.12 SDK or later.


NSTextField

With the change for NSLinkAttributeName rendering for NSLayoutManager, NSTextField now renders the link without the field editor.


NSTextView - New since WWDC seed

With macOS Sierra, NSTextView is transitioning to a new modern object ownership policy that is consistent throughout in behavior and aligned with the Automatic Reference Counting.

In previous macOS releases, NSTextView was using dual ownership policies. With the default ownership mode, NSTextView was retained by its text container forming a reverse ownership tree structure with the NSTextStorage at the root acting as the main owner of the entire object network. The secondary ownership mode was designed for developer convenience and used only by instances initialized by -[NSTextView initWithFrame:]. With the initializer, NSTextView transparently allocated the entire TextKit object network including NSTextContainer, NSLayoutManager, and NSTextStorage. In the mode, NSTextView also retained NSTextStorage effectively creating a circular reference. To workaround the circular reference issue, NSTextView was explicitly counting its references when operating in the convenience mode. This dual ownership issue was making NSTextView not compatible with the ARC weak storage.

With the new ownership policy, we are simplifying the ownership model vastly with just a single mode serving all circumstances. The ownership policy between TextKit objects are unchanged. NSTextStorage owns a list of NSLayoutManagers, and each layout manager owns a list of NSTextContainers. There are two main differences from the default mode in the previous policy: NSTextContainer weakly referencing its NSTextView and each text view always strongly referencing its NSTextStorage. With this new policy, we can serve the flexible TextKit object network as well as NSTextView's convenient behavior freeing developers from maintaining the NSTextStorage reference.

For compatibility purpose, there is a class method controlling the ownership policy introduced, +[NSTextView stronglyReferencesTextStorage]. It returns YES by default, and all instances initialized by a class returning YES operate in the new ownership policy. You can create a subclass of NSTextView overriding the factory method if needed to work in the older ownership policy. Note that such instances are not compatible with the ARC weak storage.



Notes specific to OS X 10.11

Some of the major topics covered in this section:



Swiftification

Framework APIs in both OS X 10.11 and iOS 9 have adopted new Objective-C features such as nullability, lightweight generics, and “kindof.” These features enable API intent to be expressed more precisely and APIs to come across better in Swift.

For instance we can now indicate that nil is a valid value for the destination view when converting an NSRect between coordinate systems:
- (NSRect)convertRect:(NSRect)rect toView:(nullable NSView *)view;
and that the array returned by splitting an NSString with componentsSeparatedByString: is an NSArray of NSStrings, and it will never be nil:
- (NSArray<NSString *> *)componentsSeparatedByString:(NSString *)separator;
You will notice many API changes in AppKit and other frameworks due the adoption of these new features. When building your projects against the new SDKs you may get build warnings or errors; these are important to react to since in some cases they may point out actual issues. In addition, adopting these new features in your own code should allow better compile time detection of bugs.

Please see WWDC 2015 Session 202, “What’s New in Cocoa,” for more info on this “Swiftification” effort, as well as other changes in AppKit and Foundation.



NSCollectionView

We’ve brought the power, flexibility, and scalability of iOS’ widely used UICollectionView to OS X 10.11. The new and substantially improved NSCollectionView can present heterogeneous collections of variable-sized items, allows for completely customizable layout, supports sections with optional header and footer views, and recycles and lazily instantiates items to enable scaling to large numbers of objects. For optimal performance, it is designed to be layer-backed, so be sure to run with “wantsLayer” set to YES on the CollectionView’s enclosing NSScrollView or an ancestor view.

To use NSCollectionView’s new API model, you specify a layout by setting an NSCollectionView’s “collectionViewLayout” property, and either provide a “dataSource” or bind your CollectionView’s “content” to an NSArray or NSArrayController (see “Binding Content to an NSCollectionView”, below). You must also disconnect and discard the NSCollectionView’s “itemPrototype”, which is a vestige of the 10.10-and-earlier API model.

Independently of whether you provide a dataSource or use the “content” binding, you can bind properties of your item view subtree’s controls to properties of the item’s representedObject.

The new “NSCollectionViewFlowLayout” class will be familiar to developers who’ve used UICollectionViewFlowLayout on iOS. It provides flexible layout of CollectionView items into rows or columns, and can accommodate items of variable size. Most clients can achieve their desired results using Flow layout, by adjusting its flexible parameters, implementing delegate methods, or if necessary subclassing. Completely developer-defined layouts are also possible, however, by subclassing either NSCollectionViewFlowLayout (advisable if the desired layout is similar to Flow) or its abstract base class, NSCollectionViewLayout.

To allow for optional grouping of items into sections, NSCollectionView uses the same two-level (section,item) indexing model as UICollectionView. A CollectionView’s content is composed of an ordered list of sections (one, by default), each of which contains an ordered list of items addressed by integer index within its containing section. Each (section,item) index pair that constitutes an item designation is encapsulated in an NSIndexPath, and existing NSCollectionView APIs that deal in single integer indices and NSIndexSets thereof have been replaced with uses of NSIndexPath and NSSets of NSIndexPaths. As on iOS, a set of NSIndexPath category methods helps with creating and examining individual NSCollectionView index paths:
@interface NSIndexPath (NSCollectionViewAdditions)
+ (NSIndexPath *)indexPathForItem:(NSInteger)item inSection:(NSInteger)section;
@property (readonly) NSInteger item;
@property (readonly) NSInteger section;
@end
A minimal NSCollectionView dataSource implements the two required methods of the NSCollectionViewDataSource protocol. The first required method returns the number of items to show in the CollectionView. (A single section is assumed, if the delegate does not implement -numberOfSectionsInCollectionView:.) The second required dataSource method instantiates an item for a given index path. Below is a simple example of implementing these methods, producing items in the CollectionView that represent a hypothetical NSArray of model objects:
- (NSInteger)collectionView:(NSCollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return myModelObjects.count;
}
- (NSCollectionViewItem *)collectionView:(NSCollectionView *)collectionView itemForRepresentedObjectAtIndexPath:(NSIndexPath *)indexPath {
    // Identify the model object specified by the given indexPath.
NSUInteger itemIndex = indexPath.item;
MyModelObject *modelObject = myModelObjects[itemIndex];
    // Get an NSCollectionViewItem that will represent the modelObject in the CollectionView, by sending the
CollectionView -makeItemWithIdentifier:forIndexPath: with an identifier that specifies the kind of item we want to create.
(Some CollectionViews will contain only one kind of item. Others may wish to present some objects differently, by passing
different identifier values for different model objects.) If we name our item nib “Thing.xib”, we can simply pass @“Thing”
as the identifier, and NSCollectionView will find the nib file automatically. If you prefer to use nib filenames that differ
from your item identifiers, you’ll need to register the nibs you plan to use with your NSCollectionView, using the
-registerNib:forItemWithIdentifier: method. This enables the NSCollectionView to find the desired nib based on the item
identifier you provide.
NSCollectionViewItem *item = [collectionView makeItemWithIdentifier:@“Thing” forIndexPath:indexPath];
    // Associate the item with our model object, using the “representedObject” property that NSCollectionViewItem inherits from
NSViewController. We aren’t required to set this property, but doing so will make it easy to find the item’s corresponding
model object, and facilitates binding properties in the item’s view subtree through the item’s “representedObject”.
item.representedObject = modelObject;
    // Set up any desired state in the item’s view tree.  Alternatively, we could bind control properties
through the item’s representedObject, which we set above.
item.textField.stringValue = modelObject.title;
    // Return the item.
return item;
}
When you send -makeItemWithIdentifier:forIndexPath: to a CollectionView, it first attempts to recycle an unused item of the requested type, if one is available. If a new item must be created, the CollectionView attempts to create it from an NSNib or NSCollectionViewItem subclass that was registered with the CollectionView. If you follow expected naming conventions, registering item nibs with CollectionView is unnecessary. When asked to make an item with identifier “Thing”, if no NSNib or Class has been registered with that name, NSCollectionView will first search for “Thing.nib”, then for an NSCollectionViewItem descendant class named “Thing”.

An item .nib must contain exactly one top-level instance of NSCollectionViewItem or a subclass. The item’s “view” outlet should be wired to the root of a view subtree that provides the item’s visual representation. Usually you want some sort of container view, containing TextFields, ImageViews, and other controls that display the item’s content.

Item size can be determined globally for all of a CollectionView’s items (by setting an NSCollectionViewFlowLayout’s “itemSize” property), or can be varied from one item to the next (by implementing -collectionView:layout:sizeForItemAtIndexPath: on your CollectionView’s delegate).

As before, you are completely free to determine item appearance. Items in a selectable CollectionView are responsible for visually indicating whether they are “selected”. OS X 10.11 adds a “highlightState” property to NSCollectionViewItem, that should also be taken into account when determining the visual appearance of an item. You may choose to show “selection” and “highlightState” indication by drawing the item slightly differently, or (since 10.11 CollectionViews operate layer-backed) by changing backing layer properties such as backgroundColor, cornerRadius, borderWidth, and borderColor, if you wish.

NSCollectionViewFlowLayout offers the potential to show multiple “sections” of items, each with an optional header view and/or footer view. These “supplementary” views are instantiated similarly to CollectionView items, by implementing the optional -collectionView:viewForSupplementaryElementOfKind:atIndexPath: dataSource method, and using NSCollectionView’s -makeSupplementaryViewOfKind:withIdentifier:forIndexPath: API from within it. The header view or footer view may be supplied in a nib (wherein it must be the only top-level NSView) or as a Class specified by name. Sizing of the header or footer is determined by implementing the delegate methods: -collectionView:layout:referenceSizeForHeaderInSection: and -collectionView:layout:referenceSizeForFooterInSection:, whose returned size values are constrained to the CollectionView.

NSCollectionViewGridLayout, unique to OS X, encapsulates NSCollectionView’s 10.10-and-earlier layout behavior, for those who might still want to use it in conjunction with the new NSCollectionView API model. NSCollectionViewGridLayout does not currently understand sections or provide for header or footer views. NSCollectionViewFlow layout is generally recommended as a more powerful, versatile, and flexible replacement.

NSCollectionView’s Accessibility implementation is now wired to its new API and content model. Some further refinement is still needed, but CollectionViews now successfully advertise their items (and now sections and supplementary views) for Accessibility navigation. Keyboard navigation from item to item has also been restored.

NSCollectionView now allows for customizing the inter-item-gap drop target indicator appearance, if desired. Register a NSView subclass, or a .nib containing a single top-level view, with your NSCollectionView, using -registerClass:forSupplementaryViewOfKind:withIdentifier: or -registerNib:forSupplementaryViewOfKind:withIdentifier: with a “kind” parameter of NSCollectionElementKindInterItemGapIndicator. Then watch for -collectionView:viewForSupplementaryElementOfKind:atIndexPath: to be sent to your NSCollectionViewDataSource with NSCollectionElementKindInterItemGapIndicator as the “kind”. Send -makeSupplementaryViewOfKind:withIdentifier:forIndexPath: to your CollectionView in response, passing the same identifier you registered with. NSCollectionView will use your custom view, when provided in this way, in place of its default inter-item gap indicator. Note that your view’s frame will be set to the bounding box of the inter-item gap, which might be larger than the indicator you want to draw (especially if items being dragged have been temporarily removed from the CollectionView, leaving a large layout hold behind). It’s up to you to determine an appropriate drawn size and appearance for your indicator within this bounding box, based on any knowledge you may have about the kind of layout that’s in use (Flow, Grid, or custom).

See WWDC 2015 Session 225, “What’s New in NSCollectionView,” and the accompanying “CocoaSlideCollection” code sample, for more information about configuring and using instances of the new NSCollectionView.

Binding Content to an NSCollectionView

If your NSCollectionView does not need sections or supplementary views, you may use NSCollectionView’s NSContentBinding to provide the model objects you want the CollectionView to display items for. The NSCollectionView’s “content” can be bound to an NSArrayController or to an NSArray of model objects.

An NSCollectionView that displays only one kind of item can automatically infer the item nib or class to instantiate, provided you explicitly register a single item nib or class with the NSCollectionView. For example:
    NSNib *itemNib = [[NSNib alloc] initWithNibNamed:@“MyItem” bundle:nil];
[collectionView registerNib:itemNib forItemWithIdentifier:@“item”];
In this case, you do not need to provide a dataSource. The choice of item identifier is arbitrary. — As long as the NSCollectionView finds only a single item nib or class has been registered, it will know what to instantiate.

If you need to be able to display more than one kind of item in your NSCollectionView, you’ll need to provide a dataSource in addition to the content binding. Your dataSource’s -collectionView:itemForRepresentedObjectAtIndexPath: method gives you the opportunity to determine the appropriate item identifier to use when sending -makeItemWithIdentifier:forIndexPath: (just as in the non-Bindings dataSource example above). You’ll still need to implement -collectionView:numberOfItemsInSection:, since it’s a required NSCollectionViewDataSource method, but you can implement it to simply return “collectionView.content.count”. However, since you’ve used the “content” binding to tell the NSCollectionView about your model objects, you’ll find that the items returned by -makeItemWithIdentifier:forIndexPath: will have their “representedObject” property automatically set by NSCollectionView. You do not have to find the model object that corresponds to the indexPath and manually associate it with the created item. You also don’t have to explicitly register item nibs or classes when using this approach. If you prefer, you can rely on NSCollectionView to automatically.


NSPopover

NSPopover now takes the contentInsets of containing scroll views into account when tracking a view in that scroll view. This prevents issues such as the popover pointing to a view that is obscured by the titlebar.


NSSplitViewItem animations

Animating the collapse or reveal of an NSSplitViewItem now uses implicit animations to animate from the start state to the end state. In 10.10, it would animate the constant of a constraint.

The collapse/uncollapse animation now follows a standard timing and duration. To override the animation, set a custom animation on the NSSplitViewItem for the "collapsed" key of the animations dictionary.

Animating the uncollapse of an NSSplitViewItem will now uncollapse at a priority described by its set holdingPriority, rather than at a priority of NSLayoutPriorityRequired. This gives expected behavior, consistent with an unanimated collapse of the same item.


New NSSplitViewItem properties

NSSplitViewItem has several new properties that describe the metrics associated with that item:

    •    minimumThickness and maximumThickness describe the minimum and maximum width or height of the item, and directly relate to .Required priority constraints managed by the NSSplitViewItem; setting these to NSSplitViewItemUnspecifiedDimension will cause no enforced minimum or maximum by the receiver, though the effective minimum and maximum could be determined by other constraints in the view hierarchy.
    •    preferredThicknessFraction describes the ideal percentage of the containing NSSplitView that that item takes up. This is used to return the item to that ideal fraction when the user double clicks on a neighboring divider or takes the containing window fullscreen. This does not influence how the item grows or shrinks as the split view does (the holdingPriority is responsible for that).
    •    automaticMaximumThickness describes the maximum thickness to which the item can be automatically resized. This affects the item when proportionally resized with the containing split view, or when the preferredThicknessFraction is used to size the item (double clicking on neighboring divider, entering fullscreen). Note this is not used as an absolute maximum, so the user or other constraints could still resize the item larger. Setting this to NSSplitViewItemUnspecifiedDimension will not enforce any automatic maximum.
    •    collapseBehavior describes the behavior that occurs when the item collapses and uncollapses: such as if its the containing split view (and potentially window) or the sibling items that get resized as a result. For instance, a collapseBehavior of .PreferResizingSplitViewWithFixedSiblings will attempt to the neighbor items at the current size and position on screen, typically growing the item out of the side of the window, falling back to resizing the items only if there's not enough space on screen or when in fullscreen.

When the first or last NSSplitViewItem is collapsed, if springLoaded is set to true, it will transiently uncollapse into an overlay when the user drags and hovers on the edge of the split view where the item is collapsed. Once the drag session ends, it will re-collapse. This defaults to false but should be used for collapsible items that contains drag targets, such as sidebars.


NSSplitViewItem sidebars and content lists

Sidebars in 10.11 have new behavior of automatically collapsing when the window is made smaller, and showing as overlays when at these small sizes in fullscreen. To make the notion of sidebars explicit, NSSplitViewItem has a new class constructor +sidebarWithViewController:. Sidebar SplitViewItems have the following behavior and defaults:

    •    Visual effect material background. The item's set viewController's view should not contain its own NSVisualEffectView background. NSSplitViewItem will manage this background view, ensuring a standard material for both Aqua and Dark appearances, as well as changing the EffectView's blendMode to .WithinWindow when overlaid.
    •    Vibrant divider. Similarly to the material background, neighboring dividers of sidebars are vibrantly blended with the same material as the sidebar background.
    •    Auto-collapsing and -uncollapsing on containing SplitView size changes (see -NSSplitViewController.minimumThicknessForInlineSidebars)
    •    The ability to overlay at small containing SplitView sizes when in fullscreen
    •    .minimumThickness and maximumThickness default to standard minimum and maximum sidebar sizes
    •    .preferredThicknessFraction defaults to the standard fraction for sidebars
    •    .holdingPriority defaults to the standard for sidebars. In 10.11 this is higher than the default holdingPriority, though not guaranteed in the future.
    •    .canCollapse defaults to YES
    •    .springLoaded defaults to YES

automaticMaximumThickness does not default to an explicit value for sidebars, but it should be set to the thickness at which the content is fully visible but tightly fitted (e.g. when any text stops truncating).

NSSplitViewController's minimumThicknessForInlineSidebars describes the size at which sidebars automatically collapse when made smaller, and uncollapse when made larger again. Note that if the split view is not able to made smaller than the set thickness, sidebars will not automatically collapse. When set to NSSplitViewControllerAutomaticDimension, the default, this will use the constraints in the window to determine the size for auto-collapsing. Once the SplitView can't be made any smaller during a live resize, it will auto-collapse any sidebars. Once the split view has grown large enough to where it can completely uncollapse the sidebar, it will do so. Setting an explicit size is better for performance and ensures a more consistent experience.

NSSplitViewController also has a new action method: -toggleSidebar:, which can be used to easily and animatedly collapse the first collapsible sidebar item. For instance, a main menu item can be used to toggle sidebars in the active window by setting -toggleSidebar: as its action and using nil / the first responder as its target.


Content Lists are a similar concept that has been made explicit in 10.11, with +[NSSplitViewItem contentListWithViewController:]. These are meant to be used with split panes that show a list of contents, such as Mail's message list, Photo's collection list of photos, etc. They have the following defaults:

    •    .minimumThickness defaults to the standard for content lists. Content lists do not have any standard maximum.
    •    .automaticMaximumThickness defaults to the standard absolute size for content lists.
    •    .preferredThicknessFraction defaults to the standard fraction for content lists.
    •    .holdingPriority defaults to the standard for content lists. In 10.11 this is higher than the default holdingPriority and less than that of sidebars. This is not guaranteed to stay constant in the future.


NSSplitView

NSSplitView.debugDescription now returns a description with details on how the split view is configured:
    •    Its delegate
    •    The technique it uses to layout: "constraints"/"resizeSubviews"/"resizeSubviews-autoResizingConstraints"
    •    How dividers are drawn: "views"/"layers"/"drawRect"/"notDrawn"
    •    The value of arrangesAllSubviews

In order to make the layout as flexible as possible, we recommend making sure the layout technique is "constraints". NSSplitView.debugReasonForLayoutMode will return the reason the receiver is using the layout technique it is. A common reason SplitViews cannot use constraints is that their delegate implements one of the following NSSplitViewDelegate methods:

    •    -splitView:constrainMinCoordinate:ofSubviewAt:
    •    -splitView:constrainMaxCoordinate:ofSubviewAt:
    •    -splitView:resizeSubviewsWithOldSize:
    •    -splitView:shouldAdjustSizeOfSubview:

These methods are incompatible with auto layout and are discouraged. You can achieve their effects and more with auto layout constraints.


NSSplitView Arranged Subviews

In 10.11, NSSplitView has the option to not arrange all of its subviews as split panes. By setting arrangesAllSubviews to NO (it defaults to YES), the split view is in a mode where a view added as a subview is treated as standard subview with no implications for its layout. In order to make a view be an arranged split pane, it needs to be added with -addArrangedSubview: or -insertArrangedSubview:atIndex:. Adding an arranged subview will also add that view as a subview if it wasn't already. With this, arrangedSubviews is always a subset of subviews. See header documentation for more details about the effect of setting arrangesAllSubviews and the value of arrangedSubviews.

Setting arrangesAllSubviews to NO will allow AppKit to use specialized views for the dividers, rather than drawing it on the SplitView itself. In this case, the split view now returns YES for -mouseDownCanMoveWindow, and only the divider views return NO.

NSSplitViewController objects set arrangesAllSubviews to NO by default for their owned NSSplitView.


NSStackView

NSStackView has had a significant under-the-hood overhaul. It creates significantly less constraints to accomplish its layouts, as well as removes private views from its view hierarchy, using NSLayoutGuides where needed instead. Now, added arranged views are direct subviews of the stack view, whereas there had been an intermediate view in 10.9 and 10.10. The constraints created by NSStackView all have identifiers to aid in debugging layout issues.

NSStackView has new distribution behaviors that describe how views are aligned in the stacking axis, using the distribution property.

    •    A value of .GravityAreas matches the existing behavior where views are aligned in groups along the stacking axis.
    •    Similarly .EqualSpacing matches the previous behavior of setting hasEqualSpacing to YES (which is now deprecated), where the arranged subviews fill the stack view with equal spacing between each view.
    •    A value of .EqualCentering is new behavior where the centers of the arranged views are spaced equally apart
    •    A value of .Fill is new behavior where the arranged views strongly fill the stack view along the stacking axis
    •    A value of .FillEqually is new behavior where the arranged views fill and are equally sized along the stacking axis.
    •    A value of .FillProportionally is new behavior where the arranged views fill and are sized proportionally based on their intrinsicContentSizes along the stacking axis.

New view management methods have been added to support adding arranged views with the new distribution behaviors, which do not have a notion of NSStackViewGravity for the second parameter of -addView:inGravity:: -addArrangedSubview:, -insertArrangedSubview:atIndex:, and -removeArrangedSubview:, which also correspond to the UISStackView view management methods. Using these methods to add arranged views are preferred when the distribution is not set to .GravityAreas.

NSStackView has a detachesHiddenViews property which can be set to cause hidden views to be detached from the stack view when their hidden value is YES. This also causes views that are automatically detached to become hidden rather than removed from the view hierarchy. This defaults to YES, matching the behavior of UIStackView, except for apps that are not linked against 10.11 SDK or later to match behavior on 10.9 and 10.10. Note that regardless of the value of detachesHiddenViews, the visibility priority for a view can be read/written to manage the detached views.

All added arranged views will have translatesAutoresizingMaskIntoConstraints set to NO if they had been YES. Before 10.11, it was left as-is and often led to unsatisfiable constraint exceptions if it had been YES.

Automatic detaching by using visibility priorities now reattaches views more consistently, such as in table view cells or with views who have weak intrinsic content size compression resistances.


Context Menu Callbacks

New NSView methods, -willOpenMenu:withEvent: and -didCloseMenu:withEvent:, can be used by the receiver to create visual effects for a menu being shown or dismissed against it. These will be called for contextual menus, and should be used instead of making visual changes in -menuForEvent:. They should not be used to make modifications to the passed in menu object.


View-based TableViews in Vibrant Contexts (e.g. Popovers)

In Yosemite, an NSPopover with a standard (non-source list) NSTableView with NSTextField labels would result in an incorrect appearance where the bounding boxes around the TextField would be incorrectly blended vibrantly and look inconsistent with the rest of the table view background. This is fixed in 10.11. A workaround for 10.10 is to manually set the appearance of the TableView to NSAppearanceNameAqua.


SourceList style TableViews in VisualEffectViews

In 10.11, SourceList style NSTableViews contained inside NSVisualEffectViews will inherit the containing backing rather than adding their own backing NSVisualEffectView. This containing NSVisualEffectView can be used to effectively control the blendingMode and material of the TableView's material backing. In this state, the TableView itself won't punch out content behind it, including content drawn by views between it and the containing VisualEffectView.



NSDictionaryControllerKeyValuePair changes

NSDictionaryControllerKeyValuePair is now an object rather than an informal protocol.

NSWorkspace deprecations

The NSWorkspaceLaunchOptions: NSWorkspaceLaunchPreferringClassic and NSWorkspaceLaunchAllowingClassicStartup have been deprecated. NSWorkspaceLaunchDefault has been updated to just include NSWorkspaceLaunchAsync.

The activeApplication method has been deprecated in favor of frontmostApplication.

The mountedLocalVolumePaths and mountedRemovableMedia methods have been deprecated. Use NSFileManager’s mountedVolumeURLsIncludingResourceValuesForKeys:options: instead.

The openFile:fromImage:at:inView: method has been deprecated. The image, position, and view were ignored. Use the openURL: method on NSWorkspace.

The performFileOperation:source:destination:files:tag: method has been deprecated. Many of the file operations were unimplemented, or have replacements on NSFileManger or NSWorkspace. See the individual file operations in the NSWorkspace header for replacements.

Extended Dynamic Range support

NSScreen has a new method, maximumExtendedDynamicRangeColorComponentValue, which returns the current maximum color component value for the screen. Typically the maximum is 1.0, but if any rendering context on the screen has requested extended dynamic range, it may return a value greater than 1.0, depending on system capabilities and other conditions. Only rendering contexts that support extended dynamic range can use values greater than 1.0. When the value changes, NSApplicationDidChangeScreenParametersNotification will be posted.

An NSView can request extended dynamic range by setting its wantsExtendedDynamicRangeOpenGLSurface property to YES. If any view on the screen has this enabled, the NSScreen which the OpenGL surface is on may have its maximumExtendedDynamicRangeColorComponentValue increased. When composited by the Window Server, color values rendered by this OpenGL surface will be clamped to the NSScreen’s maximumExtendedDynamicRangeColorComponentValue rather than 1.0.

NSWindow Full Screen and Spaces restoration

In previous versions of OS X, non-fullscreen windows which used NSWindow’s encodeRestorableStateWithCoder: and restoreStateWithCoder: implementations (including those that call through to super) would, on login only, have their windows restored to the space they were on previously. In OS X 10.11, this behavior has been extended to full screen windows.



NSSearchField Cancel Button Visibility

The previous behavior was that the cancel button became visible whenever the search field had focus or had text. Now, the cancel button will only show when the field contains text.

NSSearchField Notifications for Searching

Some applications present in a special mode when performing a search. For example, Finder changes the title of the window, inserts a bar with additional search options, and filters contents accordingly. Some applications continue to present a special mode after any text entered in the search field is cleared, while other applications exit the mode when text is cleared.

In an attempt to have a consistent experience, NSSearchField will now notify when the user is searching. The user is considered to be searching starting when the first action message is sent with non-empty text. Searching ends when text is cleared. We've added a new delegate protocol which will be the vehicle for these notifications.
@protocol NSSearchFieldDelegate <NSTextFieldDelegate>
@optional
- (void)searchFieldDidStartSearching:(NSSearchField *)sender;
- (void)searchFieldDidEndSearching:(NSSearchField *)sender;
@end
@interface NSSearchField : NSTextField
...
@property (assign) id<NSSearchFieldDelegate> delegate;
@end

NSSearchField Option for Centered Placeholder

We've added a new "centersPlaceholder" property that controls whether the placeholder, magnifier search button, and search menu are centered when the search field does not have focus and does not have text. With focus, the control animates its contents to the edge.

The default value for centersPlaceholder is YES since the centered-look described above was the default in Yosemite.

With the centered-look, the only way to have an empty placeholder is to use a space, “ “, since nil or the empty string will use the “Search” default. If linked on or after 10.11, only nil will result in the default, no matter what centersPlaceholder is.

Since the search field can appear centered or not, we’ve added a “centered” parameter to the custom layout methods in NSSearchFieldCell. Note that the value will not always be the same as the search field’s focus state, nor is it the same as the new centersPlaceholder parameter which states the ability to be centered. The older NSSearchFieldCell versions remain since they may be useful to those who implement custom search fields using cells.
@property BOOL centersPlaceholder;
Defaults to YES. When set, the search field's components are centered within the control if the field is empty and does not have focus. When receiving focus, given the field is empty, the centered objects will animate to the edges of the control. When this property is set to NO, the components are always at the edge. When YES, the configuration requires wantsLayer to also be YES. When NO, wantsLayer should be NO for standard appearance but can be YES for custom drawing.
- (NSRect)rectForSearchTextWhenCentered:(BOOL)isCentered;
The rectangle for the search text-field within the bounds of the search field. Subclasses can override this method for custom layout purposes. The isCentered parameter is YES when centersPlaceholder is YES and the caller is interested in the centered appearance. It is no either when centersPlaceholder is NO or when centersPlaceholder is YES and the caller is interested in the non-centered appearance. Use this instead of -[NSSearchFieldCell searchTextRectForBounds:].
- (NSRect)rectForSearchButtonWhenCentered:(BOOL)isCentered;
The rectangle for the search button within the bounds of the search field. Subclasses can override this method for custom layout purposes. The isCentered parameter is YES when centersPlaceholder is YES and the caller is interested in the centered appearance. It is no either when centersPlaceholder is NO or when centersPlaceholder is YES and the caller is interested in the non-centered appearance. Use this instead of -[NSSearchFieldCell searchButtonRectForBounds:].
- (NSRect)rectForCancelButtonWhenCentered:(BOOL)isCentered;
The rectangle for the cancel button within the bounds of the search field. Subclasses can override this method for custom layout purposes. The isCentered parameter is YES when centersPlaceholder is YES and the caller is interested in the centered appearance. It is no either when centersPlaceholder is NO or when centersPlaceholder is YES and the caller is interested in the non-centered appearance. Use this instead of -[NSSearchFieldCell cancelButtonRectForBounds:].

NSTextField maximumNumberOfLines property for wrapping text

It’s desirable for developers to restrict the number of lines of a wrapping text field, especially when the field reflows with changes in the layout. To accommodate that, we’ve introduced a new property for NSTextField called maximumNumberOfLines.
@interface NSTextField
@property NSInteger maximumNumberOfLines;
@end
For text that wraps (see NSCell’s lineBreakMode), this property determines the maximum number of lines to display. A value of 0 means there is no limit, which is the default, and the text fills the cell’s bounds. If the text reaches the number of lines allowed, or the height of the container cannot accommodate the number of lines needed, the text will be clipped (or truncated if truncatesLastVisibleLine is set). The value of this property also affects -[NSControl's sizeToFit], -[NSView fittingSize] and -[NSView intrinsicContentSize]. Most importantly, if the value of this property is not 1, multiple lines may be used to find the field’s intrinsicContentSize. Prior to 10.11, the intrinsicContentSize would be determined as if the maximumNumberOfLines was 1.

This is similar to UILabel’s numberOfLines property. There are important differences though (thus the name change). First and foremost, NSTextField’s version only works when the lineBreakMode is set to wrap, NSLineBreakByWordWrapping or NSLineBreakByCharWrapping, while UILabel’s functionality is also subject to other line break modes that clip or truncate. Our reasoning is that the maximum number of lines is a concept of the container and not the text model. They should be independent. Second, UILabel has an unfortunate affect that reflowing does not happen if preferredMaxLayoutWidth is set to any value, including 0, a value for us indicates no preferred width. We want to reflow the field especially when preferredMaxLayoutWidth is set to 0.

Here are some notes on maximumNumberOfLines’ compatibility with other NSCell text-related properties:
scrollable - Text wrapping only applies when scrollable is NO. So maximumNumberOfLines is only in affect when scrollable is not set.
wraps - This is a convenience that returns YES if lineBreakMode is word or character wrapping. Setting it to YES also sets scrollable to NO. maximumNumberOfLines then is only observed when YES.
usesSingleLineMode - When set to YES, wrapping is ignored, and if lineBreakMode is set to word or character wrapping, it is interpreted as NSLineBreakByClipping. maximumNumberOfLines then is only observed when NO.
truncatesLastVisibleLine - When set to YES, when text overflows its container, adds ellipses to the last visible line when lineBreakMode is set to word or character wrapping. So if the text exceeds maximumNumberOfLines text will be truncated when YES and clipped when NO.

When maximumNumberOfLines is not 1, auto layout can now change the width and height of the text field as long as maximumNumberOfLines (and preferredMaxLayoutWidth) is respected. Which means that the intrinsic, or natural, content size of a text field can now vary with the field’s container instead of being the size of the text that fits on a single line.

NSTextField intrinsicContentSize improvements

Previously, unless NSTextField’s preferredMaxLayoutWidth was set to something other than 0, the -intrinsicContentSize method would measure the text field with its contents on a single line, even if wrapping was enabled. Because of this behavior, the auto layout engine would not be able to find a size for a text field that spanned multiple lines, even though doing so would produce an acceptable and aesthetically better layout.

We’ve changed things such that the autolayout engine provides a width that acts like the preferredMaxLayoutWidth for the NSTextField, allowing for a text field to reflow into multiple lines. This works only for apps linked against 10.11 that have wrapping text and a preferredMaxLayoutWidth of 0. Also, it only works if the constraints on the text field allow for content compression.

Opting out:
There are some cases where you may want to opt out of the above behavior. Here are two known scenarios:
1. The height component of intrinsicContentSize may not update correctly if the string (including attributed string) contents of the text field change such that the field’s height should change but the width should remain the same. The result is a text field that either clips or is too tall. This is a known bug and you may want to opt out using the instructions below.
2. Text may wrap and the height of the text field may increase even if the line break mode of the text field is set to truncate or clip. This can occur if you have an attributed string set on the text field. When using an attributed string, its paragraph style (which includes line break mode) takes precedence over the corresponding properties of the text field and the text field cell. Also note that the default line break mode is to wrap, which means if your attributed string does not have an explicit paragraph style set, it’s assumed to wrap.

There are a few options to opt out of the new behavior, on a per text field basis. First, if the field should only have a single line of text, turn on single line mode on the text field. You can also set the maximumNumberOfLines to 1. However, if you require more than one line, you can also set the maximumNumberOfLines property to a value that makes sense - as long as it is not 0. Another option is to set a preferredMaxLayoutWidth to something other than 0 (which you have to do in code, there is no way to do this in Interface Builder). For all these workarounds, please do them as soon to creation as possible.

When using attributed strings, remember that not specifying a paragraph style is the same as using the default paragraph style, which includes a wrapping line break mode. So being explicit with a truncating or clipping line break mode is preferable.


NSGestureRecognizer Additions

NSGestureRecognizer now has a -pressureConfiguration property, allowing an NSPressureConfiguration to be automatically set by the gesture engine. When multiple gesture recognizers are active, the most compatible behavior will be set allowing for the broadest range of input. As gesture recognizers fail or begin, this effective configuration will be updated. If all gesture recognizers fail, the configuration will revert to the underlying view's configuration or the system default, as appropriate.


NSGestureRecognizerDelegate Additions

NSGestureRecognizerDelegate now allows filtering of which gesture recognizers should be allowed to participate in an event stream. This is useful for applications which don't want to subclass a built in recognizer. For example, an application might only support rotation in part of a view. On the first event which initiates the stream, the delegate will be asked if the recognizer should be allowed to recognize with the event. If YES the event processing will continue as normal. If NO, the recognizer will be excluded from the active set. Note that the recognizer will not have received the event when the delegate method is invoked, so -locationInView: will not be up to date.


NSAlignmentFeedbackFilter

AppKit provides clients with a convenient means of performing haptic feedback for alignment guides. These are used when the user is dragging an object on the screen, and the object "snaps" to known locations on screen.


While NSHapticFeedback allows clients to perform arbitrary haptic feedback, NSAlignmentFeedbackFilter helps the client perform feedback only when necessary. Often when implementing alignment guides, an application will track which object the aligned object is aligned to. A naive implementation could perform feedback when this object changes, but there are many common cases where this will perform extraneous feedback and annoy the user. The feedback filter accepts requests to perform feedback, but takes cursor velocity, snap distance, and other heuristics into account to make sure the alignment feedback feels correct.


The feedback filter uses a prepare and commit model. The app must feed the object events so that it can track cursor state. The app then asks for alignments to be prepared, and when it has chosen one or more alignments it can ask the object to perform feedback for those alignments.


The prepare methods take 3 locations. Feedback should be performed when the item jumps on screen due to alignment, so the filter has to take the previous location and the proposed alignment location. If the filter only took these two though, an item would get "stuck" as soon as it hit a guide -- how would the controller know when to release it? So, it takes a third "fallback" location which will be used if the item should become un-stuck from the guide as the user drags away.


The prepare methods come in 3 variants. Some alignments only affect the x or y coordinates, and some affect both. As such, for any given movement a controller could have multiple prepared alignments.


For every relevant event (tracking loop matching +inputEventMask), or action from gesture recognizer:
Inform the filter of the current event (-updateWithEvent: or -updateWithPanRecognizer:)
Store where the item currently is ("previousPoint")
Move the item by the appropriate delta for the mouse movement - this may be 0.0pt or several pt,
    depending on image space transformations.
Store where the item currently is ("defaultPoint")
Determine the distance you'd like to align the item (for example, 5px up to match a horizontal guide, "alignedPoint")
If alignment filter says you may move by that distance
    (-alignmentFeedbackTokenFor[Horizontal|Vertical]MovementInView:previousPoint:alignedPoint:defaultPoint:)
Perform the feedback (performFeedback:performanceTime:)
Move the item to the alignedPoint
Else
Move the item to the defaultPoint

NSWindow Split View resize increments and aspect ratio

NSWindow's resizeIncrements, aspectRatio, contentResizeIncrements, and contentAspectRatio will be ignored when determining window size in Split View. A window should do its best to fill the entire size of the tile, and these window properties would circumvent the system's ability to size two windows side by side.

Full Screen Menu Item

AppKit automatically creates an "Enter Full Screen" menu item after the application finishes launching if an equivalent menu item isn't found. If this menu item should not be created for your app, before NSApplicationDidFinishLaunchingNotification is sent you may set the NSFullScreenMenuItemEverywhere default to NO.
- (void)applicationWillFinishLaunching:(nonnull NSNotification *)notification {
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"NSFullScreenMenuItemEverywhere"];
}

Force Touch Trackpad Haptic Feedback

Haptic feedback should be performed sparingly. It should be a subtle interaction with the user during key moments of user input. Additionally, in general you should only perform haptic feedback when the input velocity strongly implies that the user is specifically trying to find the key spot. Also see NSAlignmentFeedbackFilter which can do a lot of this for you in certain circumstances.


Use the NSHapticFeedbackManager to get the default haptic feedback performer. Then ask the NSHapticFeedbackPerformer to perform the feedback. Always ask for the default feedback performer as it may change based on the user's accessibility preferences and the current input device.


NSHapticFeedbackPerformer
func performFeedbackPattern(NSHapticFeedbackPattern, performanceTime:NSHapticFeedbackPerformanceTime);

NSHapticFeedbackPatterns
    •    .Alignment - Use when visually aligning objects. This includes re-sizing, range limits, horizon alignments, etc..
    •    .LevelChange - Use when there are discreet changes due to pressure. For example, this is used by NSButton when set to NSMultiLevelAcceleratorButton type.
    •    .Generic - Use when neither of the option options are appropriate.


NSHapticFeedbackPerformanceTime
It is important that the user feel the feedback at the same time the correlated UI occurs on screen. However, you should not perform haptic feedback in the middle of drawing. Instead, set the appropriate performance time when performing haptic feedback.
    •    .DrawCompleted - Use when haptic performance should occur when the next cocoa or CoreAnimation drawing completes.
    •    .Now - Use when using OpenGL or there is no correlated UI change.
    •    .Default - Same as NSHapticFeedbackPerformanceTimeDrawCompleted.


Force Touch Trackpad Configuration

By default, the force touch trackpad is configured for deep click. That is, it will force click if the user exerts sufficient force on the trackpad while the cursor is stationary This way, the user always gets feedback that they have indeed pressed hard enough for a force click even if the app doesn't respond to it. However, this is not appropriate for all UI. For example, force clicks do not occur on the menu bar, in menus, nor during pressure-sensitive drawing.


There are two ways to configure the trackpad. Both start off with the initialization of an NSPressureConfiguration object with an NSPressureBehavior.
See NSEvent.h for the list of NSPressureBehaviors and a description of each one.
    •    Preferred - Set the pressureConfiguration property on an NSView. This is the most responsive method. The pressure configuration will be applied by the system as soon as the cursor enters the view, even if your application is not responsive yet.
    •    Alternate - Call set() on an NSPressureConfiguration object. The configuration is only applied if the user is holding the mouse down, the configuration will be reset on mouse up. Note: This means that you are racing the user. In some cases, the user may perform a mouse down and up before your application even receives the initial mouse down event. This approach is best used when you absolutely have to consult the mouseDown location before determining the correct configuration.



NSDocument Deadlock Avoidance

Autosave, iCloud Drive, and File Coordination introduced a great deal of asynchronous behavior to NSDocument. The APIs -performSynchronousFileAccessUsingBlock: and -performActivityWithSynchronousWaiting:usingBlock: were added to ensure that NSDocument operations, both UI-level and file-level, happened in a sensible and serial manner. Unfortunately, the current implementation of these APIs combined with NSDocument's historical reliance on the main thread have made these APIs vulnerable to deadlocks. A great deal of work has been done to understand and prevent these deadlocks.

A certain class of deadlock was identified that is caused by inappropriate use of the -performAsynchronousFileAccessUsingBlock:, -performActivityWithSynchronousWaiting:usingBlock:, and -continueAsynchronousWorkOnMainThreadUsingBlock: APIs. The following code demonstrates the inappropriate pattern:
[self performAsynchronousFileAccessUsingBlock:^( void (^fileAccessCompletionHandler)(void) ) {
    ... do some work asynchronously ...
    [self continueAsynchronousWorkOnMainThreadUsingBlock:^{
fileAccessCompletionHandler();
        [self performActivityWithSynchronousWaiting:YES usingBlock:^( void (^activityCompletionHandler)(void) ) {
...
activityCompletionHandler();
}];
}];
}];
While this looks innocuous, it turns out that if another activity was initiated prior to this code, and that activity called performSynchronousFileAccessUsingBlock: on the main thread after the above file access began, this code results in a deadlock. The above performActivityWithSynchronousWaiting:YES call above never returns (because the prior activity is still active). Also performSynchronousFileAccessUsingBlock:, whose blocking of the main thread was 'interrupted' by continueAsynchronousWorkOnMainThreadUsingBlock:, can never run because the 'interrupting' block never returns, resulting in deadlock.

In OS X 10.11, code to detect and avoid this particular deadlock has been added to NSDocument. When detected, NSDocument will log a message to the console starting with "An attempt was made to call performActivityWithSynchronousWaiting:YES within a block passed to continueAsynchronousWorkOnMainThreadUsingBlock:". The message will also print diagnostic information (the contents of _NSDocumentSerializationInfo()) to help you identify the call sites of performActivityWithSynchronousWaiting:YES, and other information necessary to understand the situation. Finally, NSDocument will automatically defer performing the activity via CFRunLoopPerformBlock() to avoid the deadlock.

If you encounter the above message during testing, we recommend avoiding this deadlock by deferring the above performActivityWithSynchronousWaiting:YES call until a future run loop cycle via CFRunLoopPerformBlock or similar API, or passing NO for the SynchronousWaiting: parameter.


NSSegmentedControl

NSSegmentedControls in applications linked on 10.11 or later may or may not contain subviews. Developers should not assume when enumerating subviews of an NSSegmentedControl that the subviews method will return an empty array, or that any subviews returned are only those added by the Developer or that the subviews are always of a specific class. Developers are advised to filter on view tag or identifier to find specific views they are searching for, and use respondsToSelector checks if invoking methods on random subviews of an NSSegmentedControl.

NSOpenPanel

A new property has been added to NSOpenPanel:
/* Gets and sets the disclosure state of an accessory view in an NSOpenPanel.
If hiding / disclosing an accessory view is not applicable this property will
behave like a read only property.
*/
@property (getter=isAccessoryViewDisclosed) BOOL accessoryViewDisclosed;
In 10.11, most NSOpenPanels have adopted a design that was formerly reserved only for applications which adopted iCloud Documents support and this panel design was only used if iCloud Drive was turned on in System Preferences. This note will refer to the design as the “iCloud Open Panel Design” although the design is no longer limited to applications with iCloud Documents support. The iCloud Open Panel Design introduced an NSOpenPanel behavior where accessory views are hidden by default, and an “Options” button is available in the bottom controls of the panel to disclose / hide an accessory view by user action.  To prevent unexpected UI behavior changes in 10.11, NSOpenPanels in all applications linked before 10.11 which were not already using the iCloud Open Panel Design (meaning they did not adopt iCloud Documents support) will always disclose accessory views by default. The “accessory views disclosed by default" behavior matches prior shipping OS behavior where these applications would be using the "Non iCloud Open Panel Design." If your application is linked on 10.11 or later, accessory views set on an NSOpenPanel will be hidden by default whether or not your application adopted iCloud Documents support. If you find a default hidden accessory view to be undesirable, you can use the new property of NSOpenPanel to get and set the disclosure state. It is recommended you use this property before you run or begin an NSOpenPanel. This property is not preserved between panel runs, and the value of this property is also dependent on whether an accessory view has been set, and whether the panel design supports disclosure and hiding of accessory views.

NSSavePanels do not use the iCloud open panel design and do not have disclosing / hiding accessory view functionality.  The accessory view in an NSSavePanel is always visible and cannot be hidden.


NSOpenPanel

Prior to 10.11, sandboxed open and save panels always granted a sandbox extension to the result of a successfully completed panel, even if the client of the panel did not explicitly request the results via the methods that retrieve an url or urls. The pre 10.11 behavior was relied on by some client applications, which were inferring the panel results via other means. On 10.11, clients must explicitly request the results of the panel by calling the URL or URLs methods, or a sandbox extension will not be granted, and any attempt to access the resources pointed at the by the result of the completed panel will run into sandbox access restrictions. Please add calls to the URL or URLs method to your code, even if you think you already know the result.




NSLayoutGuide

NSLayoutConstraints will now accept instances of NSLayoutGuide as layout items. This provides an easy way to calculate intermediate view geometry without having to create dummy views. Previously, dummy views were required in order to achieve equal or proportional spacing between views.


Layout Anchors

NSView and NSLayoutGuide now provide a set of properties to aid concise creation of NSLayoutConstraints. The properties are subclasses of NSLayoutAnchor, and can be used roughly like this:
NSLayoutConstraint *constraint = [myButton.leadingAnchor constraintEqualToAnchor:container.leadingAnchor constant:10];
The factory methods are available in multiple forms to allow omission of extraneous parameters, and can be activated inline if a reference to the constraint is not needed. E.g.,
[entryField.leadingAnchor constraintGreaterThanOrEqualToAnchor:label.trailingAnchor].active=YES;


NSMenuItemCell

-setTag: now sets the tag value on the cell’s NSMenuItem.

NSMenu

NSMenu now provides a userInterfaceLayoutDirection property for explicit control of the menu content layout direction. If not specified, a menu uses the layout direction of the application. The layout direction of a menu may be set explicitly in Interface Builder.

NSApplication

10.11 supports a new type of menubar behavior that hides the menubar during normal non-fullscreen interaction. The menubar shows itself automatically when the mouse moves into a hot area at the top of each display. When this mode is enabled, the NSApplication.presentationOptions property will include the NSApplicationPresentationAutoHideMenuBar value.

Prior to 10.11, the SetSystemUIMode API provided by HIToolbox, and the setPresentationOptions API of NSApplication provided by AppKit, did not allow explicitly enabling an auto-hiding menubar without also hiding the Dock. -setPresentationOptions now allows the options to contain AutoHideMenuBar without also including HideDock or AutoHideDock. To ensure compatibility with existing applications, the SetSystemUIMode API will only allow applications linked on 10.11 and later to pass the combination of kUIModeNormal and kUIOptionAutoShowMenuBar; if this combination is specified by an application linked on Yosemite or earlier, the AutoShowMenuBar option is ignored.


NSWindow / Full Screen

NSWindow will implicitly opt certain candidate windows into becoming full screen capable. An explicit full screen capable window has the NSWindowCollectionBehaviorFullScreenPrimary bit set in the window.collectionBehavior. A candidate for an implicitly full screen capable window will be a titled NSWindow that is resizable, and can resize to fit the entire screen. The exact semantics of this may change over time, and it is recommended to explicitly opt in primary document windows by including NSWindowCollectionBehaviorFullScreenPrimary in the collectionBehavior.

When in full screen, if a new window is shown the following logic takes effect: A new full screen space will be created for explicit full screen windows. For implicit full screen windows, the window will simply be shown on the current full screen space. These exact semantics may change over time.

NSWindow now supports full screen tiling (Split Screen). Full screen tiling allows two separate windows to share the same full screen space. The system will implicitly determine candidate windows for a full screen tile based on window properties, such as the window being a full screen candidate (either explicit or implicit). A window can explicitly allow or disallow itself to be tiled by including NSWindowCollectionBehaviorFullScreenAllowsTiling or NSWindowCollectionBehaviorFullScreenDisallowsTiling in the window.collectionBehavior. For example, a non resizable window may still want to explicitly allow itself to be placed in a full screen tile and would include NSWindowCollectionBehaviorFullScreenAllowsTiling. Or, a full screen capable window may want to disallow tiling; this means it will never be placed with a secondary tile window, and will always be alone when in full screen.

Once a window is allowed to be placed in a full screen tile, the system will check to see if it actually fits in a target tile for a given screen resolution. The minFullScreenContentSize is then queried, and if it fits it will be placed in a tile. In general, one does not need to set minFullScreenContentSize, and it will be implicitly determined by auto layout. If the window is not using auto layout, it will fall back to using the contentMinSize or minSize of the window. This is usually sufficient for a window that does not significantly change its layout when in full screen. However, if it does have a significant layout change, then the window can explicitly set the minFullScreenContentSize and maxFullScreenContentSize as desired. If a window wants to force allow tiling and respect any size it is given, it can include NSWindowCollectionBehaviorFullScreenAllowsTiling and set the minFullScreenContentSize to 0,0.

NSWindows in full screen will no longer get a call to constrainFrameRect:toScreen: for applications linked on 10.11 or later. Instead, the window's frame will automatically be constrained within the tile space it is allowed to be in.


NSWindow

The use of NSDrawer is discouraged. Drawers are rarely used in modern Mac apps. As much as possible, redesign your UI to avoid using drawers; if you’re creating a new app, avoid adding a drawer to the design.

In OS X 10.10.0, sheets were not offset by a custom value set for [self contentBorderThicknessForEdge:NSMaxYEdge]. In 10.11 this has been fixed for all apps.

[NSWindow windowWithContentViewController:] would always incorrectly create a class of NSWindow, even if the method was called on a subclass of NSWindow. In 10.11 this has been fixed for all apps, and applications targeting a lower OS release should not use the method unless a regular NSWindow is desired.

NSWindow's NSTitlebarAccessoryViewController now supports a layoutAttribute of NSLayoutAttributeLeft for applications linked on 10.11 or later. Prior to 10.11, more than one item with NSLayoutAttributeRight may not have been presented correctly; this has been fixed.

For applications linked on 10.11 and higher, a NSTitlebarAccessoryViewController with the layoutAttribute set to NSLayoutAttributeRight will no longer right indent toolbar items, unless the titleVisibility == NSWindowTitleHidden. This allows placing a view/button/textfield (etc) above the toolbar without right indenting the toolbar. However, for the NSWindowTitleHidden, there is still a desire to indent the toolbar on the right to leave space for the accessory view.

A borderless NSWindow with a contentView that is an NSVisualEffectView with a maskImage will correctly round the corners; previously, the corners may have been jagged. The contentView must be an NSVisualEffectView for this to happen.

Prior to 10.11, a window with titlebarAppearsTransparent=YES would not allow any views under the “virtual” titlebar area to get mouse events. Commonly this would show up in applications that place a search field in this area. This has been fixed on 10.11 for all applications.


NSTableView / NSOutlineView

NSTableView now supports a new feature dubbed “Swipe To Delete”. The delegate can implement tableView:rowActionsForRow:edge: and return an array of NSTableViewRowAction objects that represent buttons. Typically these buttons are used to delete a row, or show more information. See NSTableView’s header, and NSTableViewRowAction.h for more information.

NSTableView now has API to hide individual rows: hideRowsAtIndexes:withAnimation:, unhideRowsAtIndexes:withAnimation:, and hiddenRowIndexes. This API has been made public in 10.11, but can be used back to 10.10.2. Hiding rows may be desired when it is not possible to quickly update the datasource to represent changed data. Instead, rows can temporarily be hidden, and later deleted. Visually a hidden row looks and acts the same as a deleted row. Note that hiding a row may or may not actually set the rowView.hidden property; this is an implementation detail that may change, so do not depend on rowView.hidden necessarily being YES for hidden rows. Hiding a row that is currently selected will leave it selected; developers should un-select these rows either before or after hiding it — otherwise the user will be confused because there is a hidden row that is also selected.

NSTableView will now set the objectValue to nil for NSTableCellViews when they are removed from the table. This will help avoid unexpected references to objects when the NSTableCellViews are placed in the table's re-use queue.

NSTableView now returns the minimum frame size from the auto layout method intrinsicContentSize.

The NSTableViewSelectionHighlightStyleSourceList should now only be used when the background color has not been changed from the default color. Normally, the table adds an NSVisualEffectView to implement the blur effect, but if it detects a custom backgroundColor was set it will not attempt to do this. Previously the selection would still draw with a blur. On 10.11 the selection will now draw as a normal selection highlight style.


NSViewController

For applications linked on 10.11 and later, NSViewController has better Swift class name searching abilities to load the NIB. First, the full Swift class name will be searched for in the bundle and mainBundle, such as MyApplication.ClassName. If a NIB can not be found with that name, it will then attempt to search for just “ClassName”. This allows one to easily load a NIB by doing a simple view controller initialization without having to pass an explicit nibName.

NSVisualEffectView

NSVisualEffectView has additional materials available, and they are now organized in two types of categories. First, there are abstract system defined materials defined by how they should be used: NSVisualEffectMaterialAppearanceBased, NSVisualEffectMaterialTitlebar, NSVisualEffectMaterialMenu (new in 10.11), NSVisualEffectMaterialPopover (new in 10.11), and NSVisualEffectMaterialSidebar (new in 10.11). Use these materials when you are attempting to create a design that mimics these standard UI pieces. Next, there are specific palette materials that can be used more directly to create a specific design or look. These are: NSVisualEffectMaterialLight, NSVisualEffectMaterialDark, NSVisualEffectMaterialMediumLight (new to 10.11), and NSVisualEffectMaterialUltraDark (new to 10.11). These colors may vary slightly depending on the blendingMode set on the NSVisualEffectView; in some cases, they may be the same as another material.

Prior to 10.11, the material NSVisualEffectMaterialTitlebar would slightly round the top edges of the view (applying corners). This has been fixed for applications that use the material in locations other than the top of a window.

NSApplication

NSApplication will now crash on uncaught exceptions for applications linked on 10.11 and higher. It is highly recommended to test applications with the default: “-NSApplicationCrashOnExceptions YES” , as this enables the behavior without having to be linked on 10.11 and allows developers to catch problems.



Unification of AppKit and CoreAnimation display cycles

AppKit deferred layout and display now occur at the same time as CoreAnimation deferred layout and display. AppKit layout and drawing operations between +[NSAnimationContext beginGrouping] and +[NSAnimationContext endGrouping] will be treated as an atomic unit (this also applies to +[CATransaction begin] and +[CATransaction commit].) This can be used in place of NSDisableScreenUpdates and NSEnableScreenUpdates. The use of these two functions is discouraged. Likewise, it should no longer be necessary to use +[NSWindow disableScreenUpdatesUntilFlush] (its use is also discouraged.)


NSColorList

NSColorLists now conform to NSSecureCoding and can be securely unarchived. We encourage you to support NSSecureCoding in any custom subclasses of NSColor you may have in your applications.



TextKit for OS X

Mac OS X 10.11 introduces all the functionalities added to iOS TextKit including the exclusion paths, the maximum number of lines restriction, CGGlyph-based NSLayoutManager API, detailed layout controls via NSLayoutManagerDelegate, etc. The same TextKit API is now available for all platforms.

NSFont

NSFont now offers factory methods for querying system fonts with additional weights such as ultra light or heavy. +systemFontOfSize:weight: and +monospacedDigitSystemFontOfSize:weight: both take NSFontWeightTrait. It's recommended to use the 9 predefined NSFontWeightTrait values in NSFontDescriptor.h. When a weight that's not supported by the running environment, NSFont uses the following fallback logic.

The runtime version dependent behavior is designed to minimize impacts coming from future OS X introducing additional weights. To summarize the behavior:

(A) if the app is linked on the current or older SDK:
    return the system font corresponding to the next higher available weight (so for instance a request for unavailable SemiBold returns Bold)
    this makes sure that if a weight if supported in the future release, the space taken up the element will be no wider, and still fit
(B) if the app is linked on a future SDK:
    return the system font corresponding to the next lower available weight (so a request for unavailable SemiBold returns Medium)
    this makes sure that an element ends up taking space no wider than what it does when run on the future system

The system font APIs (i.e. +systemFontOfSize:) now returns a font instance with proportional digit glyphs. +monospacedDigitSystemFontOfSize:weight: provides access to monospaced digit glyphs.


NSFontManager

API related to NSFontDescriptor and NSFontCollection provided by NSFontManager is formally deprecated. NSFontManager is now focusing to its main task for managing text attributes of the selected object.

-[NSFontManager sendAction] was incorrectly declared as a property in previous Mac OS X releases. It is corrected and now back to be an instance method.

-fontManager:willIncludeFont: is formally deprecated. It was never implemented on Mac OS X. Developers seeking a way to filter fonts displayed to users should use NSFontCollection.


NSTextFieldCell

-[NSTextFieldCell dealloc] no longer invokes -[NSNotificationCenter removeObserver:] with itself. That behavior had a side effect of implicitly unregistering for any notification observer registered by subclasses. Now, it is the responsibility of subclasses to properly unregister.


NSTextView

-[NSTextView insertText:] is now formally deprecated. -insertText:replacementRange: from NSTextInputClient should be used as the overriding point for customizing text input behavior.


NSAttributedString

NSCharacterShapeAttributeName is deprecated. The functionality for customizing font features is available through NSFontDescriptor instead. Along with the attribute, -[NSTextView toggleTraditionalCharacterShape:] is deprecated.


Dynamic Tracking (available for OS X and iOS)

The dynamic tracking is a text feature, typically for UI elements, that a single line title attempts to tighten inter-character spacing/tracking for fitting into a narrower space before truncation. It's controlled by a new NSParagraphStyle property, -allowsDefaultTighteningForTruncation . The behavior is similar to OS X feature controlled by -[NSParagraphStyle tighteningFactorForTruncation]. The main difference is that the range of ratio between the line and available space is automatically determined for the API clients (based on information coming from fonts) with the new text feature unlike the existing API controlling the ratio explicitly.  -tighteningFactorForTruncation!=0.0 enables the existing tightening behavior when -allowsDefaultTighteningForTruncation state=YES with binaries linked with Mac OS X 10.11 or later SDK. For pre-10.11 binaries, -tighteningFactorForTruncation is always preferred regardless of -allowsDefaultTighteningForTruncation value. Also, explicitly setting 0.0 to -tighteningFactorForTruncation has a side effect of disabling -allowsDefaultTighteningForTruncation. -allowsDefaultTighteningForTruncation is YES by default for apps linked against Mac OS X 10.11 or later SDK. It's disabled for pre-10.11 applications and on iOS.



NSText

NSTextAlignment enums (NSTextAlignmentLeft, NSTextAlignmentRight, etc) is replacing the existing values. The old values are informally deprecated.

NSAttributedString

NSTextWritingDirection is replaced by NSWritingDirectionFormatType. NSTextWritingDirection is formally deprecated.

NSUnderlineByWordMask is replaced by NSUnderlineByWord. NSUnderlineByWordMask is formally deprecated.

-[NSAttributedString containsAttachments] is replaced by -containsAttachmentsInRange:. -containsAttachments is informally deprecated.

Document format reading methods (i.e. -[NSAttributedString initWithURL:documentAttributes:]) without NSError arguments are now deprecated.

-[NSAttributedString URLAtIndex:effectiveRange:] is deprecated. NSDataDetector is the preferable replacement.

NSLayoutManager

NSGlyph and related APIs are replaced by CGGlyph-based TextKit counterparts. NSGlyphAttribute and NSGlyphInscription are replaced by NSGlyphProperty.

New CGGlyph-based API:
    -CGGlyphAtIndex:isValidIndex:
    -CGGlyphAtIndex:
    -setGlyphs:properties:characterIndexes:font:forGlyphRange:

The API for receiving the editing notification from NSTextStorage, -textStorage:edited:range:changeInLength:invalidatedRange: is replaced with -processEditingForTextStorage:edited:range:changeInLength:invalidatedRange.

There are additional functionalities brought over from iOS TextKit. Developers can now identify line fragments that are truncated with -truncatedGlyphRangeInLineFragmentForGlyphAtIndex:. Bounding rects enumeration APIs, -enumerateLineFragmentsForGlyphRange:usingBlock: and -enumerateEnclosingRectsForGlyphRange:withinSelectedGlyphRange:inTextContainer:usingBlock:, are replacing the old NSRectArray-based APIs.

NSLayoutManagerDelegate is enhanced with more text layout customization abilities previously only available through NSTypesetter subclassing. Sophisticated dynamic capabilities such as glyph substitution, dynamic line fragment override, line break point override, are provided to NSLayoutManager delegates.

We're deprecating the screen font support formally. Applications could either provide a UI feedback to users asking permission upgrading to the floating-point font metrics or keep using the deprecated APIs.

NSTextTab

NSTextTabStyle and corresponding methods are deprecated. +[NSTextTab columnTerminatorsForLocale:] is added for conveniently instantiating decimal tab stops.

NSStringDrawing

NSStringDrawing API from iOS TextKit is introduced for OS X. NSStringDrawingContext for handling additional options along with methods taking it as an argument are added. Corresponding existing methods without NSStringDrawingContext argument are deprecated.

NSTextAttachment

NSTextAttachment API based on NSData and UTI from iOS TextKit is introduced for OS X. The new API is not relying on an external NSTextAttachmentCell object and offers more flexibilities in controlling various rendering aspects of the attachment contents without requiring to subclass NSTextAttachment or NSTextAttachmentCell. For developers requiring the dynamic layout aspect of NSTextAttachmentCell, a new NSTextAttachment protocol, NSTextAttachmentContainer, can be overridden.

The designated initializer is changed from -initWithFileWrapper: to -initWithData:ofType:. The default implementation of -initWithFileWrapper: invokes the new designated initializer with nil arguments, then, sets -fileWrapper property. Applications targeted for Mac OS X releases prior to 10.11 should override both old and new designated initializers.

NSTextContainer

Matching iOS TextKit, the -containerSize property and -initWithContainerSize: are replaced with -size and -initWithSize:. We're adding a TextKit semantics for the -size property that 0.0 indicates the infinite value.
Along with the method renaming, we're moving the designated initializer to -initWithSize:. The default implementation of -initWithContainerSize: just invokes -initWithSize:.

The TextKit enhancements for NSTextContainer providing powerful container shape customization capabilities are introduced to Mac OS X 10.11, too. -exclusionPaths, -lineBreakMode, and -maximumNumberOfLines allow richer layout customization previously available only by overriding -lineFragmentRectForProposedRect:… method.

-lineFragmentRectForProposedRect:sweepDirection:movementDirection:remainingRect: is replaced by -lineFragmentRectForProposedRect:atIndex:writingDirection:remainingRect:. The layout engine invokes the former method if it's overridden. The old API along with NSLineSweepDirection and NSLineMovementDirection are informally deprecated.

-containsPoint: is now deprecated.




Notes specific to OS X 10.10.3

OS X SDK corresponding to Yosemite 10.10.3 brings support for the Force Touch trackpad on the MacBook and the early 2015 13” MacBook Pro. These notes describe those updates.



Note that many (but not all of the APIs) described here are available on machines shipping with the Force Touch trackpad and machines updated to 10.10.3 or newer. Look for “NS_AVAILABLE_MAC(10_10_3)” or similar availability indication.

Pressure Events

The new Force Touch trackpad has the ability to report pressure. Like the rotation and magnification gestures that came before it, the pressure gesture is reported as a new event type, NSEventTypePressure, and a new responder method -pressureChangeWithEvent:. The new NSEventTypePressure event is only available in 64 bit.

NSEventTypePressure is a fluid gesture. And like all fluid gestures, it has a phase that describes the sequence of the pressure gesture stream:
@property (readonly) NSEventPhase phase;
A pressure gesture can go through multiple stages:
@property (readonly) NSInteger stage NS_AVAILABLE_MAC(10_10_3);
Stage 0: The lowest stage. Generally this means the user is applying less pressure than what is required to get a mouse down. Effectively you only see one stage 0 pressure event per stream when the gesture ends.
Stage 1: Equivalent to a mouse down. NSEventTypePressure events are not posted until the user applies enough pressure that the trackpad will also issue a mouse down.
Stage 2: Equivalent to a force click. The user has applied significant additional pressure greater than what is needed for a mouse down. Stage 2 should generally be used as the trigger for an additional action. For example, lookup is performed when the pressure stream transitions to stage 2.
Note: Generally, the trackpad will actuate as the gesture transitions across stages.
Note: It is possible for stage to increase or decrease multiple integer values per change. For example, a quick removal of the user’s fingers while at stage 2 may cause stage to transition to 0 without a pressure event with stage 1.
@property (readonly) float pressure;
The pressure on the trackpad for the current stage. The range for this value is [0,1]. Each stage has a pressure curve appropriate for that stage. That is, pressure may change from [0,1] for stage 1. And likewise, [0,1] for stage 2.
Note: Pressure of only one stage should be used. Carefully consider the use case. If variable input is useful for all cases, then use the pressure during stage 1 as this is the most comfortable range for the user. If variable input is useful only in rare situations where the user input must not be ambiguous with a regular mouse click, then use stage 2. Though, generally, for such cases, use stage 2 to denote this input and ignore stage 2 pressure. Do not attempt to combine stage 1 and stage 2 pressure to get a larger range. Doing so will cause undue stress on the user’s fingers.
Note: pressure is not appropriate for weight measurements.
@property (readonly) CGFloat stageTransition NS_AVAILABLE_MAC(10_10_3);
The animation value for stage transitions. Positive stageTransition describes approaching the next stage of the pressure gesture. Negative stageTransition describes approaching release of the current stage. For example, as the user approaches stage 2, stageTransition will increase towards 1. The moment the gesture transitions to stage 2, stageTransition immediately return to 0 and will decrease towards -1 as the user releases pressure on the trackpad until the gesture transitions to stage 1 again. Generally, only the positive stage transition values are animated.
Note: stageTransition doesn’t match the pressure curve. There are bands where the pressure may change but the stageTransition remains at 0. stageTransition remains at 0 until the gesture is very near a stage transition.
@property (readonly) NSEventMask associatedEventsMask NS_AVAILABLE_MAC(10_10_3);
This property makes it possible to determine on the mouse down if pressure should be expected from the input device. Since pressure and mouse events are independent streams, you sometimes need to make a decision (for example, a starting pressure) immediately on mouse down.
Example:
  if (event.associatedEventMask & NSEventMaskPressure) {
self.pressure = 0; // Pressure events are coming!
} else if (event.subtype == NSTabletPointEventSubtype) {
self.pressure = event.pressure; // tablets embed pressure in the mouse event.
} else {
self.pressure = 1; // This device does not have pressure. Default to full pressure
}

Getting Pressure Events

There are 3 ways to get pressure events.
1. Override the NSResponder method:
    -(void)pressureChangeWithEvent:(NSEvent *)event;
2. In a tracking loop, add NSEventMaskPressure to the eventMask.
  NSEventMask eventMask = NSLeftMouseDraggedMask | NSLeftMouseUpMask | NSEventMaskPressure;
[self.window trackEventsMatchingMask:eventMask timeout:NSEventDurationForever mode:NSEventTrackingRunLoopMode handler:^(NSEvent *event, BOOL *stop) {
if (event.type == NSEventTypePressure) {
// yay, pressure!
} else if (event.type == NSLeftMouseUpMask) {
*stop == YES;
}
}];
or:
  NSEvent *event = [self.window nextEventMatchingMask:NSLeftMouseDraggedMask | NSLeftMouseUpMask | NSEventMaskPressure];
3. In a NSGestureRecognizer subclass by overriding the method:
    -(void)pressureChangeWithEvent:(NSEvent *)event;

Spring Loaded Drag & Drop

The Finder spring loading feature has been expanded and adopted in more places. All application windows will spring forward automatically. Tabs will activate themselves in response to spring loading while segmented controls and buttons can be configured to respond to spring loading.

Spring loading is triggered by hovering over a spring loading capable target. The length of the hover delay is controlled via the Accessibility Mouse & Trackpad system preference pane.

Using a pressure sensitive trackpad, the user can also trigger spring loading by pressing harder on the trackpad during a drag. This is akin to a nested click inside of a drag. During a drag, the user can press harder. The trackpad will actuate, arming the spring loading under the cursor. When the user relaxes just enough to release the nested click, the trackpad will actuate and trigger the spring loading without dropping the drag. Once the user triggers spring loading via a pressure sensitive trackpad, the hover feature is disabled until the user starts a new drag & drop operation.

Spring Loaded Controls

Segmented controls and buttons can be configured to send their action in response to the user dragging an item. Set springLoaded to YES and the user will be able to interact with the control via force clicking or hovering during a drag. This property causes action on force-click or extended hover while dragging. Defaults to NO.
@property (getter=isSpringLoaded) BOOL springLoaded NS_AVAILABLE_MAC(10_10_3);

Spring Loaded Tab View

Tab views and tab view controllers now change selection in response to forcek click or extended hover while the user is dragging an item.

Accelerator Buttons

There are new button types for pressure sensitive trackpads, referred to as "accelerator" buttons.  These act like continuous-mode push buttons in that applications generally respond to them while they are held down, and then stop when they are released.  Their main feature is the ability to interpret variable pressure, allowing the user to directly control the speed of the related action by changing the pressure they apply.  This is intended to be used for things like controlling the speed of fast forward and rewind for media playback, the advancement speed for week view in calendar, or the zoom speed in maps.

There are two types of accelerator buttons:
• A "regular" type where fine-grained precision is desirable, and the range of values is a floating point number.  Here the button's value is 0 when not pressed, and ranges from [1...2) when pressed.
• A "multi-level" type with a configurable number of explicit levels (up to 5).  These buttons also present a value of 0 when not pressed, but have an integer value from [1...N] to indicate the discrete acceleration levels.
typedef NS_ENUM(NSUInteger, NSButtonType) {
NSAcceleratorButton NS_ENUM_AVAILABLE_MAC(10_10_3),
NSMultiLevelAcceleratorButton NS_ENUM_AVAILABLE_MAC(10_10_3),
}
// Configures the maximum allowed state for NSMultiLevelAcceleratorButton buttons, allowed values range from [1,5].
@property NSInteger maxState NS_AVAILABLE_MAC(10_10_3);
The new button types are variants of the standard NSMomentaryLightButton, and work with a variety of bezel styles.  A simple call to setButtonType is all that's necessary to use them -- this will properly configure relevant aspects of the button.  Accelerator buttons behave differently than standard NSButtons in a variety of ways.  Beyond the additional API above, here are the major behavioral distinctions:
* Accelerator buttons do not have a value equal to their state.  Instead, their value conveys the variable acceleration amount.
* Actions work slightly differently for accelerator buttons -- they will change value and send action messages repeatedly while interacting with the user.  On mouse up, they reset their value to 0 and send a final action message.
* The value of a multi-level accelerator button can be explicitly set in order to suppress lower levels of the accelerated range.  This is used, for example, when a video is already fast forwarding at 4x: we provide no acceleration messages or feedback until the 8x level is reached.
* Accelerator buttons allow a greater range of values: [0,1.99999...] or [0,5] compared to the standard on/off/mixed for other buttons.
* Accelerator buttons do not support mixed state, and in fact state is not generally useful for them (as with regular pushbuttons).

All accelerator buttons will carry a state of 0 when not pressed, or 1 when pressed/clicked normally.  The value will rise above 1 when pressed harder.  For fine grained control over speed, NSButtonTypeAccelerator exposes a doubleValue ranging from 1 when initially pressed to 1.999999 (or so) when fully pressed.  This design allows the doubleValue and integerValue to "match", and avoids having to expose a separate property for the fractional part of the value.

An NSMultiLevelAcceleratorButton provides a configurable number of distinct pressure levels, with tactile feedback as the user reaches each one.  Clients configure the number of discrete levels by changing the new maxAcceleratorLevel property.  It is always 1 for other button types, but defaults to 2 for multi-level accelerator buttons.  Values outside the range [1,5] will be pinned and cause a warning to be logged.  Values above 1 will add additional levels to the button, with a light actuation, on capable hardware, when each one is reached.  The control takes on these integer values during interaction with the user, and sends an action message whenever they change.  As an aside, note that the pressures needed to reach a given level remain the same, regardless of the maxAcceleratorLevel.  In other words, the pressure thresholds for the allowed levels are not evenly spread across the available pressure range.  Instead, they are consistent between buttons configured with different maxAcceleratorLevels, so if it takes 200g to reach level 2 on a 5-level button, it will be the same for a 2-level button.

Applications respond to accelerator buttons using the traditional action handlers.  They read the control's state/integerValue or doubleValue, and configure the speed of the related operation to match.  The application is responsible for translating the floating point [0,1.99999] or integer [0,5] values into an appropriate speed for their specific use case.

When an accelerator button is configured with continuous=YES, it will not send actions when the value changes (as pressure changes or on mouse up).  Instead, it sends actions out periodically at a variable rate dependent on the pressure.  The rate used is based on the interval configured with -setPeriodicDelay:interval:, but is adjusted dynamically based on the pressure applied to allow both slower and faster action rates.  This is roughly consistent with how the 'continuous' property works for other button types, and is useful for clients who simply want an action message when it's time for them to flip to the next page, etc.  Calling -setButtonType:NSAcceleratorButton will also reconfigure the periodic delay & interval.

Accelerator Segmented Controls

Segmented controls can be configured for pressure sensitivity, which can be used to accelerate user interactions. For example, a -/+ zoom control may want to accelerate zooming the harder the user presses. A continuous control with a periodic interval may accelerate page turning, as the periodic interval is automatically adjusted based on pressure.
typedef NS_ENUM(NSUInteger, NSSegmentSwitchTracking) {
    NSSegmentSwitchTrackingMomentaryAccelerator NS_ENUM_AVAILABLE_MAC(10_10_3) = 3, // accelerator behavior, only selected while tracking
}
/*  This message is valid only for trackingMode=NSSegmentSwitchTrackingMomentaryAccelerator and provides the double value for the selected segment.
*/
- (double)doubleValueForSelectedSegment NS_AVAILABLE_MAC(10_10_3);
The control may have its tracking mode set to NSSegmentSwitchTrackingMomentaryAccelerator. doubleValueForSelectedSegment represents the value which the individual segment would return without any segment offset, as if it were a standalone accelerator button.

Accelerator Segmented Control Behaviors

Behavior of momentary accelerator segmented controls vary based on the state of their continuous flag and whether or not the hardware supports pressure sensitivity. Below is a description of the behavior in each configuration.

Continuous Momentary Accelerator, non-pressure sensitive trackpad:
Actions will be sent at the cell's periodic interval, starting after the cell's periodic delay. Upon mouse up a final action will be sent with selectedSegment=-1.

Continuous Momentary Accelerator, pressure sensitive trackpad:
Actions will be sent at a periodic interval automatically adjusted based on pressure, starting after the cell's delay. Upon mouse up a final action will be sent with selectedSegment=-1. In this configuration the adjusted periodic interval is useful for accelerated page turning of content.

Non-Continuous Momentary Accelerator, non-pressure sensitive trackpad:
An initial action will be sent with doubleValueForSelectedSegment=1.0. Upon mouse up a final action will be sent with doubleValueForSelectedSegment=0.0 and selectedSegment=-1.

Non-Continuous Momentary Accelerator, pressure sensitive trackpad:
Each time the pressure changes, an action will be sent with doubleValueForSelectedSegment=[1.0+pressure]. Upon mouse up a final action will be sent with doubleValueForSelectedSegment=0.0 and selectedSegment=-1. In this configuration the doubleValueForSelectedSegment is useful to accelerate actions such as zooming.



Notes specific to OS X 10.10

Some of the major topics covered in this section include:



Swift

Swift is a new programming language for Cocoa and Cocoa Touch that provides many innovative features while also seamlessly operating with Cocoa APIs and Objective-C. You can find documentation, release notes, and other resources for Swift development on the Apple developer website.

We expect Swift to change and evolve rapidly before Swift 2.0, and we also expect to update the way Objective-C APIs come through in Swift. In the meantime, some items of note regarding the interaction of Swift with existing Cocoa APIs in 10.10 Yosemite:

• Instance methods in Cocoa APIs come across to Swift pretty much as-is. A method such as:
- (BOOL)setResourceValue:(id)value forKey:(NSString *)key error:(NSError **)error;
in Swift looks like:
func setResourceValue(value:AnyObject?, forKey key:String, error:NSErrorPointer) -> Bool
The first part of the Objective-C name appears as the first part of the Swift name, outside the parens, and the labels on the second and subsequent arguments appear as labels in Swift as well.

In both cases, "value" and "key" are simply the names of the local variable corresponding to the first and second arguments, and are not part of the method name.

Important to note that the Swift name of such a method includes the labels, so the name of such a method would be read as in ObjC, as "setResourceValue forKey error", not "setResourceValue." Removing the names of the arguments, the method signature is:
func setResourceValue(AnyObject?, forKey:String, error:NSErrorPointer) -> Bool
So basically Objective-C instance method names are exposed automatically and without any changes in Swift.

init methods are also exposed automatically, but there is a mapping: Both init methods and convenience constructors are exposed in Swift as constructors. In such cases if present, "with" is dropped, and all the arguments, including the first one, have an explicit label. So a method such as:
- (instancetype)initWithTimeIntervalSinceNow:(NSTimeInterval)secs;
is exposed as:
convenience init(timeIntervalSinceNow secs: NSTimeInterval)
and the same thing happens with a convenience constructor such as:
+ (NSColor *)colorWithPatternImage:(NSImage *)image;
which appears as:
init(patternImage image: NSImage) -> NSColor
• As you can see in the above examples, some Objective-C Cocoa types are mapped to their Swift counterparts, such as NSString/String above. Also note that by-ref NSError return arguments (NSError **) appear as NSErrorPointer in Swift. id appears in Swift as AnyObject, and NSArray appears as AnyObject[]. NSInteger is mapped to Int, and in most cases so is NSUInteger.

• Cocoa structs such as NSRange and NSSize are available to Swift with custom constructors, such as:
let size = NSSize(width: 20, height: 40)
• To localize strings in your applications you can use the NSLocalizedString(key:tableName:bundle:value:comment:) function. This function provides default values for the tableName, bundle, and value arguments, so you can use it in a variety of forms, shortest being:
result = NSLocalizedString("Update", comment:"Title of button the user can click to update account info")
• Enums in Cocoa which follow the "common prefix" naming guideline (which applies to the more recent enums) appear in Swift with the common prefix removed. For instance:
typedef NS_ENUM(NSInteger, NSByteCountFormatterCountStyle) {
    NSByteCountFormatterCountStyleFile,
    NSByteCountFormatterCountStyleMemory,
    NSByteCountFormatterCountStyleDecimal,
    NSByteCountFormatterCountStyleBinary
};
is exposed in Swift as:
enum NSByteCountFormatterCountStyle : Int {
    case File
    case Memory
    case Decimal
    case Binary
}
and you can refer to the individual values as NSByteCountFormatterCountStyle.File or just .File in appropriate contexts.

• Objective-C selectors appear using the Selector type in Swift. You can construct a selector with a string literal, such as
let action: Selector = "updateAccountInfo:"


Storyboards

AppKit has new API to support the Storyboarding feature being introduced in OS X 10.10.

The NSStoryboard class (declared in NSStoryboard.h) provides the means to access your app’s storyboards and instantiate controllers by name. (You can also specify an NSMainStoryboardFile in your app’s Info.plist, which causes the named storyboard to be automatically loaded, and its initial controller instantiated and presented, at app launch time.) Both NSViewController and NSWindowController have a new, readonly “storyboard” property, that returns the NSStoryboard (if any) that the controller belongs to.

The NSStoryboardSegue class (declared in NSStoryboardSegue.h) encapsulates a named connection from a sourceController to a destinationController, while the NSSeguePerforming protocol, to which both NSViewController and NSWindowController now conform, provides the means to hook into the mechanics of these transitions. When your app performs a segue, the segue’s destinationController is presented. The presented destinationController remains shown until it is dismissed (usually in response to a user action).

To dismiss a ViewController or WindowController, you send it (or have it send itself) the new -dismissController: message. -dismissController: is declared as an IBAction, so you can wire it up as the destination of a target-action connection if you wish.

NSWindowController

NSWindowController has a new “contentViewController” property, that mirrors the “contentViewController” property of the associated window. An NSWindowController that’s part of a storyboard is required to have a contentViewController — a requirement that Xcode’s storyboard editor assists you in fulfilling when you drag an NSWindowController into the storyboard canvas.

As is always the case when new properties or methods are added to an OS X framework class, those additions may interfere with the operation of identically named properties or methods in 3rd party code. When this happens, developers are advised to rename their properties or methods to avoid problems. On OS X 10.10, AppKit strives to maintain compatibility for apps linked before 10.10, by sensing the case where an NSWindowController subclass declares a “contentViewController” ivar and a “-contentViewController” getter method, but no “-setContentViewController:” setter method. In such cases, NSWindowController’s -setContentViewController: method (which will now be invoked in place of a synthesized setter, at nib-unarchiving time for example) sets the subclass instance’s “contentViewController” ivar to help affected code continue to operate. This workaround is no longer applied once the app is linked on OS X 10.10 or later, so in the long term, an affected app should rename its “contentViewController” ivar and getter, to ensure they continue to operate as intended. AppKit also avoids invoking its own contentViewController getter and setter methods, for apps linked before OS X 10.0 that would have no knowledge of this new property.

Prior to OS X 10.10, an NSWindowController only received -windowWillLoad, -loadWindow, and -windowDidLoad messages when the NSWindowController itself performed the nib loading — that is, when the NSWindowController was instantiated in code and given the name of a nib file to load on demand when its -window was first requested.  This meant -windowWillLoad, -loadWindow, and -windowDidLoad would not be sent to an NSWindowController that was loaded as one of a nib file’s constituent objects.

AppKit now sends -windowWillLoad, -loadWindow, and -windowDidLoad to an NSWindowController that’s unarchived from a nib, if the NSWindowController is wired up to an associated window.  An override of -windowDidLoad can count on all connections described in the nib having been established.  The documented behavior of -isWindowLoaded has changed slightly to match: For an NSWindowController unarchived from a nib, -isWindowLoaded reports NO at first, then YES at the time -windowDidLoad is invoked and thereafter.  To prevent binary incompatibility problems due to these changes in long-standing NSWindowController behavior, the changes described in this paragraph only take effect for apps linked on or after OS X 10.10, when running on OS X 10.10 or later.



NSViewController

NSViewController now has a suite of methods for presentation hooks: -viewWillAppear, -viewDidAppear, -viewWillDisappear, and -viewDidDisappear. See the header comments in NSViewController.h for more details.

NSViewController now has a -viewDidLoad method that can be overridden for instances that want to know when the view has been loaded, and can do additional setup work as needed. To maintain compatibility for apps that may invoke their own, identically named “-viewDidLoad” methods, AppKit invokes -viewDidLoad only for apps linked on or after OS X 10.10.

NSWindow now has a contentViewController property. This property makes it easy to assign the contentView of a window using a view controller. There is also a convenience method for creating a titled window: [NSWindow windowWithContentViewController:]. See the NSWindow.h header comments for more details.

NSViewController now has the following new features, all commented in great detail in NSViewController.h:
• Parent/child container view controller methods
• View controller presentation options
• View controller transition options

NSViewController now conforms to the NSUserInterfaceItemIdentification protocol. This allows it to participate in the Transparent Application Lifecycle management. Any NSViewController can now use the suite of methods declared on NSResponder for state restoration: encodeRestorableStateWithCoder:, restoreStateWithCoder:, invalidateRestorableState, and restorableStateKeyPaths.

NSViewController now has a suite of methods to control layout for its associated view: updateViewConstraints, viewWillLayout and viewDidLayout. See the NSViewController.h header for more information.

The following changes take effect for applications linked on 10.10 and higher:

• NSViewController automatically adds itself into the responder chain. When a view is assigned, the view's current nextResponder is saved off. The view's nextResponder is then set to be the viewController, and viewController's nextResponder is set to be the previously saved nextResponder. When the view has a call to setNextResponder: made, the method will be forwarded to the view’s view controller. If you currently are already doing your own responder chain management, take particular care as the view.nextResponder may already be the NSViewController. This can cause an issue for apps that manually set the viewController.nextResponder = view.nextResponder, without checking to see if the view.nextResponder != viewController; otherwise, an infinite loop may be created, causing an application to hang. To debug these hangs, run the application with “-NSResponderDebugResponderLoops YES”. This option will check the responder chain for loops anytime setNextResponder is called (note that this option will slow down program execution).

Put another way, the responder chain with view controllers looks like this:

ChildView -> ParentView -> ParentView’s ViewController -> ParentView’s ParentView -> Window -> Window’s WindowController.

• loadView: would previously not have well defined behavior if there was a "nil" nibName. On 10.10 and later, if nibName is nil NSViewController will automatically try to load a nib with the same name as the classname. This allows a convenience of doing [[MyViewController alloc] init] (which has a nil nibName) and having it automatically load a nib with the name "MyViewController".


Auto Layout

For apps linked against 10.10 and later, recalculating a window’s key view loop will layout any dirty subtrees in the window. Previously, the key loop would be calculated using the dirty layout frames, potentially leading to an incorrect key view loop. This affected layouts created with constraints as well as with NSStackView.

Constraints that span over parent views (e.g. a button within a container view constrained to a sibling of the container view) that are created in IB are no longer removed at runtime. Apps running on systems earlier than 10.10 will still have this issue — a workaround for apps deployed on earlier systems is to create the affected constraints programmatically.

Constraints from a Leading or Trailing edge of one layout item to the Center X of another no longer behave unexpectedly (such as causing unsatisfiable constraints) in RTL environments. Apps running on systems earlier than 10.10 will still have this issue — a workaround for apps deployed on earlier systems is to use explicit Left or Right attributes in RTL environments.

NSPopover

The responder chain no longer ends at the NSPopover window. That window now has a nextResponder of its parentWindow, i.e. the window of the positioningView.

The contents of popovers shown from borderless windows and status bar items are now focusable. In these cases, the popover window will become the key window. Transient popovers shown from these contexts will also properly close.

If the popover’s contentView returns NO from -acceptsFirstResponder, the popover will no longer make it the first responder. This can be utilized to show help text popovers without making the source lose first responder or key status.

Calling the -close method on a popover will now cause child popovers to be forced closed as well (in accordance with past documentation). Calling -performClose: will still fail if the popover has a nested popover.

-popoverWillClose: is now called on the delegate before the popover queries its animates property to determine if it should animate. This allows the pattern of always having animates = NO, and turning it on in willClose: and willShow: to animate showing and closing the popover.

In OS X 10.10, NSPopover now positions its content flush to the edges of the popover. Previously it was inset (2, 2, 2, 2).

Detachable Popover Improvements

NSPopoverDelegate’s new -popoverShouldDetach:. This is called when the user begins dragging the popover to determine if it should be allowed to detach. If the delegate does not implement this method, the default behavior will be NO.

An app wanting to use a custom detached window vended from -detachableWindowFromPopover: will need to implement this method to return YES if linked against 10.10 or higher. Apps linked before this will continue to work as expected without the method implementation.

Automatically created detachable windows. If the delegate returns YES from -popoverShouldDetach:, but does not implement or returns nil from -detachableWindowForPopover:, a detached window will be automatically created to detach to. This will reuse the contentViewController’s view as its contentView, and maintain a popover-like appearance with a seamless transition during the detach. During the detach with an automatic window, -PopoverShould/Will/DidClose notifications will not be sent. Instead, when the automatic window is going to be closed, -popoverShouldClose: will give the delegate a chance to prevent the closing of the window, and PopoverWill/DidClose notifications will be sent if it does close. If -showRelativeToRect:ofView:preferredEdge: is called on the popover while an automatically created detached window is shown, the popover will not appear, but the detached window will be made key and ordered front. Once the detached window is closed, calling -showRelativeToRect:ofView:preferredEdge: will return to showing the popover.

-detachableWindowForPopover: will only be called once the popover is going to be fully detached, not when the user begins the drag. This means that the popover appearance during the drag will be based on the popover itself, rather than the final detached window. -popoverShouldDetach: should be used to indicate that the popover should be allowed to be dragged and detached.

-popoverShouldClose: is no longer called on the delegate or popover when the window is detaching to a separate window.

Popover Appearance Changes

In order to allow for appearance customization through NSAppearance, NSPopover’s appearance property is transitioning from type NSPopoverAppearance to NSAppearance. If you plan to deploy to 10.10 or above, the former is considered deprecated, and you should no longer set or read the appearance property with NSPopoverAppearanceMinimal or NSPopoverAppearanceHUD. If you are deploying to 10.10 as a minimum, the appearance property is declared as taking an NSAppearance. If no appearance is specified, the effective appearance defaults to NSAppearanceNameVibrantLight. This corresponds to the appearance created by NSPopoverAppearanceMinimal. NSPopoverAppearanceHUD has no parallel style in NSAppearance.

Apps linked against 10.9 and earlier will have the NSAppearanceNameAqua appearance set on their popover content, while apps linked against 10.10 and later will not (and will inherit the VibrantLight appearance from the popover). This is to prevent unintended vibrancy effects (see the NSVisualEffectView section for a deeper description of these effects) in apps that were not prepared for them. However, when building an app for Yosemite, these possible vibrancy side effects should be kept in mind in popovers.

NSSplitView

In 10.10, SplitViews using auto layout will now correctly hide the first and last dividers when the delegate returns such from -splitView:shouldHideDividerAtIndex:. In 10.9 and earlier, these dividers would fail to hide.

In 10.10, SplitViews using auto layout will respect when its userInterfaceLayoutDirection is NSUserInterfaceLayoutDirectionRightToLeft. Its subviews and dividers will be ordered from Right to Left; i.e. subview 0 is the right-most view and divider 0 is the right-most divider. SplitViews not using auto layout will continue to not order views right-to-left.


NSSplitViewController

NSSplitViewController is a new container view controller class in 10.10. It manages an NSSplitView to layout its child view controller’s views. The use of NSSplitViewItem objects expose the SplitViewController specific properties of a child view controller in the NSSplitViewController.

One benefit of NSSplitViewController is the lazy loading of childViewControllers’ views. In general the performance benefits of this may not be as significant as NSTabViewController’s lazy loading, but does come into play in a couple situations: (1) when setting up the SplitViewController and adding SplitViewItems, the children’s views will not be loaded until the SplitViewController’s is loaded, and (2) when adding a collapsed SplitViewItem to a SplitViewController; the item’s view will only be loaded once the view is uncollapsed (programmatically or by the user). If it is never uncollapsed, it is never loaded by SplitViewController.

The use of auto layout with NSSplitViewController allows an app to customize whether the collapse of a split view item causes, for instance, the window to stay the same size or shrink without exposing any additional API or requiring the developer to do additional work. If the constraints used to create the layout of a child view controller’s view hierarchy are not enough to describe the behavior during collapse/uncollapse, NSSplitViewItem’s holdingPriority property can be set to specify this behavior.

The collapsed property of NSSplitViewItems are KVC/KVO compliant. This allows developers to do things like bind a PushOnOff button to the collapsed state of the item. As the button is toggled, so is the split view item. And vice versa: if the SplitViewItem is collapsible and the user collapses the the item (with a drag or double click), the button’s state is updated:
[toggleButton bind:NSValueBinding
toObject:sidebarSplitViewItem
withKeyPath:@"collapsed"
options:@{NSValueTransformerNameBindingOption : NSNegateBooleanTransformerName}];
Since the collapsed property is also animatable with the SplitViewItem's animator proxy, the binding could be instead written against the animator property. This gives all the same benefits as the previous example, but now when the button is toggled, the split view item’s view controller will be animated in or out:
[toggleButton bind:NSValueBinding
toObject:[sidebarSplitViewItem animator]
withKeyPath:@"collapsed"
options:@{NSValueTransformerNameBindingOption : NSNegateBooleanTransformerName}];

NSStackView

For layer-backed StackViews, views are no longer clipped to any private container bounds. This change only affects apps linked against 10.10. NSStackView now overrides +requiresConstraintBasedLayout to return YES, allowing StackViews to properly function in windows that do not have any other constraints.


Dark Menus

Dark menu support is enabled by users via the General preferences pane. It’s a system-wide setting, not per application, and it is intended to apply to a small number of system elements — menu bar, menus, dock, and cmd-tab application switcher. It does not apply to application windows.

NSStatusItem appearance and Dark Menu support

There are a number of stylistic changes added and supported by NSStatusItem, including appearance changes for Dark Menus. Use template images to ensure correct styling based on the various states the status item can be in (light menu, dark menu, inactive light, inactive dark, selected, disabled, etc). NSStatusBarButton’s appearsDisabled property can be used to give the image a disabled or “off” look without having the item be functionally disabled. The -button property has been added to give access to the NSStatusBarButton that is internally created and displayed in the status item. Existing properties that had previously been forwarded to this button are softly deprecated and should be accessed directly through the button. The button property also allows screen position measurement (such as for use with popovers) without setting a custom view.

Creating a standard status item with proper styling can be done in a just few lines:
NSStatusItem *myStatusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength];
gearImage.template = YES;
myStatusItem.button.image = gearImage;
myStatusItem.button.accessibilityTitle = @"My Status Item";
myStatusItem.button.appearsDisabled = networkIsDisabled;
myStatusItem.menu = myStatusItemMenu;

The view property of NSStatusItem is softly deprecated as well as API meant to support its use. The custom view property alone is not enough for AppKit to provide standard styling for the different status item states and enables items to look and feel out of place in the menu bar. Please file enhancement requests if NSStatusItem & NSStatusBarButton’s API does not allow for a behavior that should be standardized and allowed.


NSTabViewController

NSTabViewController is a new container view controller class in 10.10. It provides:
• Lazy loading of non-visible view controllers
• Easy design time construction with Storyboarding
• A target for bindings
• Easy/abstract hookup for displaying large content switches
• A way of providing standard tab-style UI with external controls

NSTabViewController represent an abstract target for providing content switching. tabViewItems and selectedTabViewItemIndex are KVC/KVO compliant. This allows one to bind an NSSegmentedControl (or other bindable objects) directly to them:
[segmentedControl bind:NSContentBinding toObject:tabViewController withKeyPath:@"tabViewItems" options:nil];
[segmentedControl bind:NSSelectedIndexBinding toObject:tabViewController withKeyPath:@"selectedTabViewItemIndex" options:nil];

Right to Left UI

• NSComboBox will now correctly flip when its userInterfaceLayoutDirection is NSUserInterfaceLayoutDirectionRightToLeft.
• NSDatePicker will now correctly flip when its userInterfaceLayoutDirection is NSUserInterfaceLayoutDirectionRightToLeft.
• NSPopupButton will now correctly flip when its userInterfaceLayoutDirection is NSUserInterfaceLayoutDirectionRightToLeft.
• NSSearchField will now correctly flip when its userInterfaceLayoutDirection is NSUserInterfaceLayoutDirectionRightToLeft.
• NSSplitView will layout its subviews from right to left when its userInterfaceLayoutDirection is NSUserInterfaceLayoutDirectionRightToLeft and is using auto layout.

Sheet Appearance Changes

Sheets shown from windows will inherit the appearance of their sheet parent window — for instance, a sheet shown from a window with a VibrantDark appearance will also have a VibrantDark appearance. An appearance can be specifically set on a sheet and override the inherited appearance. If the sheets have a vibrant appearance, their content will be vibrantly blended, and potential unintended vibrant side effects should be kept in mind in sheets (see the NSVisualEffectView section for a deeper description of these effects).


NSDatePicker changes

On applications that build against the 10.10 SDK, when running on 10.10 or later, NSDatePicker and NSDatePickerCell’s setLocale: and setTimeZone: methods will copy the given locale/time zone instead of simply retaining it.

NSDatePicker now supports the Chinese lunar calendar when the calendar property is set to an NSCalendar created with the NSCalendarIdentifierChinese identifier.

NSDatePicker’s NSClockAndCalendarDatePickerStyle now supports RTL according to its locale.

NSTokenField property behavior changes

On applications that build against the 10.10 SDK, when running on 10.10 or later, NSTokenField and NSTokenFieldCell’s setTokenizingCharacterSet: methods will copy the given character set instead of simply retaining it.

NSSpeechRecognizer property behavior changes

On applications that build against the 10.10 SDK, when running on 10.10 or later, NSSpeechRecognizer’s setCommands: method will copy the given array instead of simply retaining it.

NSWorkspace methods for passing configuration and options when opening a URL

NSWorkspace now has a pair of methods for opening URLs with specific configuration options. See openURL:options:configuration:error: and openURLs:withApplicationAtURL:configuration:error: in AppKit/NSWorkspace.h.

NSScreen behavior changes

NSScreen instances are now immutable — their properties will not change. To get updated information as displays are reconfigured, listen for the NSApplicationDidChangeScreenParametersNotification and, when it arrives, get new NSScreen instances, which will have the updated information.

NSScreen isEqual will now return YES for the same display even if the NSScreen instances are not identical.

On applications that build against the 10.10 SDK, when running on 10.10 or later, [NSScreen screens] will return an empty array if no displays are attached instead of nil.


Handoff support in AppKit

NSUserActivity is a new class in Foundation which encapsulates the state of a user activity in an application on a particular device, in a way that allows the same activity to be continued on another device in a corresponding application from the same developer. Examples of user activities include editing a document, viewing a web page, or watching a video.

There are new APIs on the NSApplication delegate to support continuing an activity from an NSUserActivity. There is also a userActivity property on NSResponder and NSDocument that lets AppKit manage calling -becomeCurrent and -invalidate, along with -updateUserActivityState: and -restoreUserActivityState: methods that can be overridden to save/restore your own state in the NSUserActivity.

Additionally, document based apps can put NSUbiquitousDocumentUserActivityType in each CFBundleDocumentTypes entry in the Info.plist and AppKit will automatically create NSUserActivities for documents in iCloud (that are accessible from the userActivity property). Activity types specified in this way do not need to appear in the Info.plist NSUserActivityTypes array, which is used to declare the activities supported by the application.

NSUserActivities that have the NSUserActivityDocumentURLKey set in their userInfo can be automatically continued using NSDocumentController’s openDocumentWithContentsOfURL:display:completionHandler:. NSDocument will put its fileURL in the userInfo with NSUserActivityDocumentURLKey in its implementation of updateUserActivityState:.

For more information, see Foundation/NSUserActivity.h and AppKit/NSUserActivity.h.

New NSTokenField styles

NSTokenField has two new tokenStyles: NSTokenStyleSquared and NSTokenStylePlainSquared. NSTokenStyleSquared is the recommended style for most token fields. NSTokenStylePlainSquared is recommended for instances where tokens appear as labels.

The existing NSTokenStyle enum values: NSDefaultTokenStyle, NSPlainTextTokenStyle, NSRoundedTokenStyle are deprecated. You should use NSTokenStyleDefault, NSTokenStyleNone, and NSTokenStyleRounded instead.


NSAppearance

An accessor has been added to get the name of an appearance instance.

NSAppearanceNameLightContent has been deprecated. Uses of this appearance will be redirected to the default Aqua appearance.

Vibrant appearances, NSAppearanceNameVibrantDark and NSAppearanceNameVibrantLight, have been added, for use with NSVisualEffectView.

NSTextView

The default insertion point color is now [NSColor controlTextColor]. In the Aqua appearance this color is black and therefore should result in no change in behavior, but in other appearances (e.g. Vibrant Dark) it may be different.



Gesture Recognizers

Gesture recognizers are now available in AppKit. The API is nearly identical to the UIKit version. See NSGestureRecognizer.h. There is a NSGestureRecognizer (NSSubclassUse) category that is explicitly meant for subclassers to override and call. Non-subclassers should never directly access these category methods and properties.

The following are considered physical gestures:
• A mouse button press, (possibly) drag, and release. Note: each button is an independent gesture stream.
• A gesture which always goes through NSEventPhaseBegan and NSEventPhaseEnded / NSEventPhaseCancelled (aka Rotate and Magnify)
Note: while ScrollWheel events have a phase value, the phase is not required, and thus ScrollWheel events are not capture-able by NSGestureRecognizers.

Gesture recognition begins at the moment any of the above physical gestures begin. At this point, the set of possible gesture recognizers is gathered much like UIKit. That is, the set of all gesture recognizers attached to the hit tested view and its ancestor views. From there, all mouse, keyboard, and gesture events are routed to the set of gesture recognizers even if such events are the start of a different physical gesture. This continues until the complete set of gesture recognizers end (or fail) or all physical gestures that have begun since the first one, have completed.

Gesture Recognizers do not see events that are pulled by event tracking loops. For this reason, it is advised that your gesture recognizer subclass delay events of the type you are processing (see the various delays[type]Event properties on NSGestureRecognizer).

The event passes from NSApplication’s -sendEvent: to any event monitors, then to NSWindow’s -sendEvent: method then to Gesture Recognizers and finally out to the responder chain. At any point in this chain the event may be consumed. If a gesture recognizer is delaying events, the events are consumed once a gesture is recognized. If all gesture recognizers fail then the delayed events are routed to the window’s responder chain. Warning: consuming events that mark the end of a gesture before Gesture Recognizers handle them can cause the gesture recognizers to get confused.

The set of AppKit provided gesture recognizers (and their UIKit analogs) are:
• NSPanGestureRecognizer [UIPanGestureRecognizer] - tracks a mouse drag
• NSClickGestureRecognizer [UITapGestureRecognizer] - tracks a specified number of clicks (button press and release)
• NSPressGestureRecognizer [UILongPressGestureRecognizer] - tracks a press and hold
• NSMagnificationGestureRecognizer [UIMagnificationGestureRecognizer] - tracks a magnification gesture event sequence
• NSRotationGestureRecognizer [UIRotationGestureRecognizer] - tracks a rotation gesture event sequence


Block Based Event Tracking

There is a new block based event tracking method on NSWindow. It will continuously track events using the supplied tracking handler block until the tracking handler block explicitly terminates tracking.
- (void)trackEventsMatchingMask:(NSEventMask)mask
timeout:(NSTimeInterval)timeout
mode:(NSString *)mode
handler:(void(^)(NSEvent *event, BOOL *stop))trackingHandler;
If a matching event does not exist in the event queue, then the main thread blocks in the specified runloop mode until an event of the requested type is received or the timeout expires. If the timeout expires, the tracking handler is called with a nil event. A negative timeout is interpreted as 0. Use NSEventDurationForever to never timeout. Tracking continues until *stop is set to YES in the tracking handler. This method returns once tracking is terminated.

Calls to -nextEventMatchingMask:… are allowed inside the trackingHandler block. This is often useful to quickly drain the event queue for coalescing purposes.



NSScrollView

NSScrollView now has a contentInsets property similar to that of UIScrollView in iOS. Typically this is used with NSFullSizeContentViewWindowMask when the scroll view intersects the title / tool bar.

“Automatically” sets the scroll view's contentInsets property to account for any overlapping title / tool bar. In order to overlap with the title / tool bar the window style mask must include NSFullSizeContentViewWindowMask and the titlebar must not appear transparent. Normally this is NSEdgeInsetsZero. Defaults to YES.
@property BOOL automaticallyAdjustsContentInsets;
NSScrollView manages a number of subviews (contentView, scrollers, find bar, rulers, etc..). This property controls the distance that the subviews are inset from the enclosing scroll view during tiling. When contentInset equal to NSEdgeInsetsZero, traditional tiling is performed. That is, the rulers, headers, etc... are tiled with the contentView frame filling the remaining space. When contentInset is not equal to NSEdgeInsetsZero, the rulers, header, etc... are inset as specified. The contentView is is placed underneath these sibling views and is only inset by scroll view border and non-overlay scrollers. Note: if automaticallyAdjustsContentInsets == YES then any value set here will get overridden during tiling.
@property NSEdgeInsets contentInsets;
The distance the scrollers are inset from the edge of the scroll view:
@property NSEdgeInsets scrollerInsets;

NSClipView

Since NSClipView is the view that actually contains the scrollable content (documentView), NSClipView also gains the concept of contentInsets.

When YES, and used as the contentView of an NSScrollView, the scroll view will automatically set the appropriate clipView contentInsets considering the scrollView’s contentInsets, boarder and layout of other subviews such as rulers and headers. Defaults to YES.
@property BOOL automaticallyAdjustsContentInsets;
The distance that the content view is inset from the enclosing scroll view. Animate with [self animator]. If automaticallyAdjustsContentInsets == YES then any value set here will get overridden during tiling.
@property NSEdgeInsets contentInsets;
Generally, the default automatic behavior will do the right thing when using a full content view style window. To achieve a hidden pull down or pull to refresh style UI, set automaticallyAdjustsContentInsets to NO and manually set the contentInsets. Add the hidden content as subViews of the clipView and place arrange them above your documentView’s frame.



NSPrintSaveJob and File Coordination

In Mac OS X 10.9, when printing operations resulted in PDF or PostScript files, NSPrintOperation would use NSFileCoordinator to properly cooperate with other applications that might be presenting or accessing the same file. However, this new behavior caused deadlocks in some applications doing their file coordination, since coordinated writing on the same file from two separate subsystems is not reentrant

The scenario where these would occur always involved an app correctly doing a coordinated write, then inside that write running an NSPrintOperation with NSPrintSaveJob set with an explicit value for NSPrintJobSavingURL (the URL provided by the coordinated write). In order to break this deadlock NSPrintOperation on Mac OS X 10.9.2 or later will not perform a coordinated write if and only if both NSPrintSaveJob and NSPrintJobSavingURL are set.

If NSPrintSaveJob is set but NSPrintJobSavingURL is not, then NSPrintOperation will still perform a coordinated write. The same goes for when a print operation starts off with NSPrintSpoolJob, the print panel is displayed, and the user chooses to Save to PDF instead of sending the job to the printer.

Non-main thread invocations of -[NSDocumentController typeForContentsOfURL:error:]

Prior to Mac OS X 10.10, it was possible for -[NSDocumentController typeForContentsOfURL:error:] to be invoked on a non-main thread. This is no longer the case. However, if your application targets Mac OS X 10.9 or earlier and overrides this method, you should make sure the method is safe to be invoked on a non-main thread.



Gradual deprecation of NSCell

Mac OS X 10.10 takes another step towards the eventual deprecation of cells. Direct access to the cell of a control is discouraged, and methods which allow it will be formally deprecated in a subsequent release. A variety of cell-level APIs have been promoted to various Control subclasses in order to provide cell-free access to important functionality. NSLevelIndicator, NSTextField, NSSearchField, NSSlider, and NSPathControl all have new properties for this purpose. Cell-based NSTableViews are now deprecated, and view-based NSTableViews should be used instead. Matrix-based NSBrowsers are also deprecated in favor of the item-based interface.


NSPathControl

In order to discourage direct access to cells, Mac OS X 10.10 adds a new item-based API to NSPathControl. This eliminates the need to use NSPathComponentCell to manage the components of the path. Additionally, a variety of properties have been added to NSPathControl which provide access to important functionality previously only available through NSPathControlCell.


NSForm

Use of NSForm is now deprecated. Use NSTextField directly, and consider using NSStackView if layout assistance is desired.


NSMatrix

Use of NSMatrix is informally deprecated. We expect to add the formal deprecation macros in a subsequent release, but its use is discouraged in the mean time. The primary use of NSMatrix is for radio button groups, so recall that for applications linked on 10.8 or later, radio buttons that share the same parent view and action will operate as a group.


Weak targets for NSControl & NSCell

The target properties of control and cell subclasses have been modified to provide proper automatic-zeroing weak reference behavior for applications linked on Mac OS X 10.10 and higher. The implementation attempts to accommodate targets which cannot be safely referenced weakly, but the result is that messages are now sent to targets at the time they are set. If a target is being set to an invalid object reference or an object in the process of deallocation, this can cause crashes in cases that were previously innocuous. One consequence of this change is that NSControl now has a concrete implementation of the target & action properties. This is something to be aware of if you plan to rely on it in 10.10, but also deploy your application to previous releases.


New Auto Layout Constraint Management API

Under Mac OS X 10.10, it is now possible to directly activate and deactivate NSLayoutConstraint objects, without having to worry about adding them to an appropriate ancestor view. This is accomplished by manipulating NSLayoutConstraint's new boolean property 'active'. Class methods are available for operating on multiple constraints simultaneously, which can be much faster. The legacy API on NSView for adding & removing constraints is now deprecated.


Image positioning in Buttons

NSButtonCell now uses -imageRectForBounds: to position images displayed in buttons, for applications linked against Mac OS X 10.10 or later.



NSTableView/NSOutlineView General Updates

NSTableRowView now has properties to determine if the previous and/or next row is selected. This is useful for drawing selection differently based on this state.
@property(getter=isPreviousRowSelected) BOOL previousRowSelected;
@property(getter=isNextRowSelected) BOOL nextRowSelected;
NSTableView now supports the ability to statically design the contents of a table at design time in Xcode. At runtime, it is unarchived and identical to what you designed.

One can also dynamically create a static table view with a new property: usesStaticContents.

Normally, a table view will only keep around a subset of the total number of rows potentially available (in general, this is limited to the visible region, plus some overdrawn allowance for responsive scrolling). A static table view keeps all views added to the table around when usesStaticContents=YES. Views can dynamically be removed by calling removeRowsAtIndexes:withAnimation:. The datasource does not need to implement numberOfRowsInTableView: when usesStaticContents=YES. Static views are encoded and decoded with the table view. Views can also dynamically be inserted into the table view by using insertRowIndexes:withAnimation:, however, this requires an implementation of tableView:viewForTableColumn:row: to provide the newly inserted view, which is then kept around statically.

NSOutlineView also supports the ability be statically designed, and works similarly to NSTableView. However, to dynamically change the outline view you must use the methods: insertItemsAtIndexes:inParent:withAnimation:, removeItemsAtIndexes:inParent:withAnimation:, and moveItemAtIndex:inParent:toIndex:inParent:. Provide newly inserted items by implementing the datasource method outlineView:child:ofItem:, and indicate they are expandable by implementing outlineView:isItemExpandable:. It is not necessary to implement outlineView:numberOfChildrenOfItem when using a static outline view. Note that all items provided must be encodable (i.e.: implement the NSCoding protocol), and unique (in order to uniquely identify the row for a given item).

Since 10.5, NSTableViews/NSOutlineViews are configured as sidebars (source lists) by setting the selectionHighlightStyle to NSTableViewSelectionHighlightStyleSourceList. This has always had side effects. Specifically, it will control some layout metrics for NSOutlineView and NSTableView. Upon setting the style, it will also set the backgroundColor of the tableView to a special internal color. Prior to 10.10 this color was a light blue gradient. After 10.10, an NSVisualEffectView is internally used to create a blurred background. After setting the style, one could always change the color away from the internal default; doing this will cause the blur background to not be shown (which may be desired). On 10.10, setting the selectionHighlightStyle to NSTableViewSelectionHighlightStyleSourceList will now also set the appearance to NSAppearanceNameVibrantLight. On 10.10, for source lists using the rowSizeStyle of NSTableViewRowSizeStyleDefault, the intercellSpacing.height is now automatically controlled. In general, it may vary based on the user's set row size style in System Preferences, and it is important to test each size when creating a “source list” application.

In 10.10, NSTableHeader view now has a new height. Applications linked on 10.10 and higher will automatically get the new default height. For applications not linked on 10.10, the new height will still be applied, but only in cases where there are no overrides in drawing for NSTableHeaderView or NSTableCellView.

Animations

Most animations on the system can be slowed down by setting the default NSAnimationSlowMotionOnShift to YES and holding down the shift key. NSTableView previously had use a default named NSTableViewSlowMotion; it is no longer used.


NSWindow

NSWindow has some API to control the new look of windows in OS X.

The first new API is titlebarAppearsTransparent; when set to YES, the titlebar does not draw its background, allowing all content underneath it to “show through.” It is only applicable to use this option when turning on the new NSFullSizeContentViewWindowMask option for the window styleMask. NSFullSizeContentViewWindowMask can be combined with titled windows (using NSTitledWindowMask) to allow a contentView’s frame to be the full size of the window and take up space under the toolbar/titlebar. Doing this may still require certain UI pieces to not appear under the titlebar/toolbar; to find that area, utilize the contentLayoutRect and contentLayoutGuide. Please also refer to the notes about the contentInsets property and related new features in NSScrollView to see how to use NSFullSizeContentViewWindowMask in advanced situations.

Another new property is called titleVisibility and the enum options are:
typedef NS_ENUM(NSInteger, NSWindowTitleVisibility) {
/* The default mode has a normal window title and titlebar buttons. */
NSWindowTitleVisible = 0,
/* The always hidden mode hides the title and moves the toolbar up into the area previously occupied by the title. */
NSWindowTitleHidden = 1,
};
The method canStoreColor is now deprecated; it has not been used in some time.

NSWindow has never supported clients adding subviews to anything other than the contentView. Some applications would add subviews to the contentView.superview (also known as the border view of the window). NSWindow will now log when it detects this scenario: "NSWindow warning: adding an unknown subview:". Applications doing this will need to fix this problem, as it prevents new features on 10.10 from working properly. See titlebarAccessoryViewControllers for official API.

NSWindow now has the ability to add officially known subviews to the titlebar/toolbar area. The views are to be wrapped with a new NSViewController subclass called NSTitlebarAccessoryViewController and added to the window with the "titlebarAccessoryViewControllers" API. There are a set of methods to add and insert the titlebarAccessoryViewControllers, such as addTitlebarAccessoryViewController: and removeTitlebarAccessoryViewControllerAtIndex:. However, one can also utilize "removeFromParentViewController" to easily remove a given child view controller. NSTitlebarAccessoryViewController has a property to tell NSWindow where to place the view (layoutAttribute) and a property to determine how it behaves in full screen (fullScreenMinHeight). The NSToolbar fullScreenAccessoryView API is now deprecated, and clients should utilize this new API.

HUD style windows (utilizing the NSHUDWindowMask) now automatically utilize NSVisualEffectView to create a blurred background. Applications should set the NSAppearance with the name NSAppearanceNameVibrantDark on the window to get vibrant and dark controls.

NSView

shouldDrawColor is now deprecated. It has not meant anything meaningful in quite some time, and should not be used.

The "gState" class of functions in NSView (and some auxiliary classes) are now deprecated. In many cases, they did not do anything, and their use was not well defined.

NSSegmentedControl

NSSegmentedControl (and the underlying cell) properly respect the isBordered flag for applications linked on 10.10 and higher. The value is saved with the normal encoding routines. By default, the cell will have setBordered:YES done in init.


Yosemite's Translucent Backgrounds and Vibrancy / NSVisualEffectView

Translucent backgrounds and associated "vibrancy" in Yosemite are supported by a new view class, NSVisualEffectView. “Vibrancy” describes a compositing mode that does special blending such as “Plus Darker”, “Plus Lighter”, “Color Dodge”, and “Color Burn.” It is automatically used by the system in many places, including pop-overs, “source list” and sidebar table views, and sheets. Some dynamically use vibrancy based on their contents; for example, NSTextField does when certain special colors are used, such as the new colors: [NSColor labelColor] and [NSColor secondaryLabelColor].

If you need to support vibrancy in one of your own views, the following conditions must be met:
• The view must be contained inside an NSVisualEffectView.
• The view must return YES from allowsVibrancy.
• The view’s effectiveAppearance must return YES from allowsVibrancy (this means it must be either the NSAppearanceNameVibrantLight or NSAppearanceNameVibrantDark appearance). (Typically you set the appearance on the window, or on the NSVisualEffectView, and the subviews will inherit the appearance.)

NSVisualEffectView’s internal implementation of blurring and vibrancy depends on the blendingMode. If the blendingMode is set to NSVisualEffectBlendingModeBehindWindow, then blurring is achieved by describing a rectangle to the window server that should be blurred. Areas that should be vibrant are also described in a similar way. Once a particular region is described to be vibrant, ANYTHING drawn in that region will be drawn vibrant, even things drawn drawn before the vibrant subview. Therefore, once a view returns YES from allowsVibrancy, both it and all of its subviews will always be vibrant—a subview can not turn off vibrancy by returning NO from allowsVibrancy. For example: consider a large square NSView that returns NO from allowsVibrancy which fills its contents with [NSColor blueColor]. Consider an NSTextField that is on top of this blue view, and the NSTextField returns YES from allowsVibrancy. The square bounding frame for the NSTextField will become vibrant, including the blue color beneath, which will look wrong (the blue rectangle under the text will be a darker blue). The solutions to this problem: The blue view should also be vibrant, and return YES from allowsVibrancy. Or, the NSTextField needs to opt-out of vibrancy. Opt-ing out of vibrancy can be done by one of the following: setting the appearance back to NSAppearanceNameAqua OR using controlTextColor OR overriding allowsVibrancy and returning NO. It is possible to opt-out rectangular 100% opaque views by adding another NSVisualEffectView, and subviews to it that return NO from allowsVibrancy. These overlapping siblings will not be vibrant, but ONLY works for the blending mode NSVisualEffectBlendingModeBehindWindow. Not that this will only respect the rectangular shape.

If the blendingMode is set to NSVisualEffectBlendingModeWithinWindow, then the use of Core Animation layers is required. It is best to call view.wantsLayer = YES on the parent view that contains the NSVisualEffectView, as blurring will occur with it and the children of the NSVisualEffectView. Blurring for NSVisualEffectView is achieved by using special Core Animation filters. Vibrancy for a particular subview that returns YES from allowsVibrancy is achieved by setting the layer.compositingFilter. Applications that have vibrant views should not change the layer.compositingFilter for a view. A layer’s compositingFilter applies to how the layer and all of its children are composited to the parent layer, and it is not possible to have a child view to NOT be vibrant. However, you can add sibling views over the vibrant view; the overlapping sibling views will correctly not be vibrant. Note this ONLY works for the blending mode NSVisualEffectBlendingModeWithinWindow.

It is not recommended to subclass NSVisualEffectView and override -drawRect: or -updateLayer.

NSVisualEffectView with the NSVisualEffectBlendingModeWithinWindow blending mode can not overlap a view with the behindWindow blending mode; doing so will cause drawing artifacts. Similarly, behindWindow can not overlap withinWindow.

Note that a hidden NSVisualEffectView may still have a performance impact; at this time it is better to remove it from the view hierarchy.



NSImage changes to named image lifetime

Beginning in Mac OS X 10.10 named images are retained. Previously, named images had been weakly referenced (and occasionally cached.) This allows applications to register a named image using the -[NSImage setName:] API, and retrieve it later using the +[NSImage imageNamed:] API. To achieve the same pattern on prior releases, it was necessary to hold an extra reference to the image. Applications wishing to ensure named images are deallocated must call -[NSImage setName:] with nil, before releasing their reference to the image. Note that changing the name of system artwork, or bundle artwork loaded through +[NSImage imageNamed:] is not supported.

NSImage support for sliced images

The resizingMode property of an image defines how that image is drawn into a rectangle larger or smaller than that image's natural size. When drawn into a larger rectangle NSImageResizingModeTile will replicate the image like a pattern. When drawn into a smaller rectangle the image will be clipped. NSImageResizingModeStretch will resize the image to fit precisely into the specified rectangle. Both modes have no effect when the image is drawn into a rectangle of its native size. NSImageResizingModeStretch is the default, and matches the behavior of previous releases.

The capInsets property allows the image to have specific regions that are stretched or tiled independently, based on resizingMode. In both modes the corners defined by the capInsets property are drawn without scaling or tiling. When the resizingMode is NSImageResizingModeTile, the horizontal edges will be replicated vertically, the vertical edges will be replicated horizontally, and the center of the image will be replicated on both axes. When the resizingMode is NSImageResizingModeStretch, the horizontal edges will be stretched vertically, the vertical edges will be stretched horizontally, and the center of the image will be stretched on both axes.

Note that drawing an image into a rectangle smaller than its natural size will cause the edges and corners to be stretched to fit into that rectangle.

NSBitmapImageRep support for image data byte-swapping

In Mac OS X 10.10 NSBitmapImageRep now supports explicitly specifying the endianness of image data. This can be accomplished by using the new NS16BitLittleEndianBitmapFormat, NS32BitLittleEndianBitmapFormat, NS16BitBigEndianBitmapFormat, and NS32BitBigEndianBitmapFormat enumerations. These behave equivalently to the CGBitmapByteOrder enumerations. Setting no byte order option produces behavior identical to MacOSX 10.9. Setting more than one byte order option is illegal.

Importantly 8-bit BGRA image data can be expressed by passing bitsPerSample=8, samplesPerPixel=4, bitmapFormat=NSAlphaFirstBitmapFormat|NS32BitLittleEndianBitmapFormat, and bitsPerPixel=32 to -[NSBitmapImageRep initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpace:bitmapFormat:bytesPerRow:bitsPerPixel:].

NSOpenGLContext conformance to NSLocking

NSOpenGLContext now conforms to the NSLocking protocol. -[NSOpenGLContext lock] and -[NSOpenGLContext unlock] should be considered equivalent to CGLLockContext([NSOpenGLContext CGLContextObj]) and CGLUnlockContext([NSOpenGLContext CGLContextObj]).

NSOpenGLContext getter for associated pixel format

It is now possible to access the pixel format associated of an OpenGLContext using the -[NSOpenGLContext pixelFormat] method.

Changes to -[NSView noteFocusRingMaskChanged]

-[NSView setNeedsDisplay:] and -[NSView setNeedsDisplayInRect:] used to call -[NSView noteFocusRingMaskChanged]. In OS X 10.10 this is no longer the case. Views must manually make the call -[NSView noteFocusRingMaskChanged]. This enables views to redraw portions of themselves without needlessly redrawing their focus rings, which can be expensive.

New NSGraphicsContext CGContext methods

In MacOSX 10.10 NSGraphicsContext offers two new methods, +graphicsContextWithCGContext:flipped: and -CGContext. These methods are exactly the same as the existing +graphicsContextWithGraphicsPort:flipped: and -graphicsPort methods, excepting that they are typed to accept and return CGContextRef respectively. The old methods will be deprecated in a future release.


NSColor

NSColor exposes new system colors in 10.10 for static text and related elements: labelColor, secondaryLabelColor, tertiaryLabelColor, and quaternaryLabelColor. The first two are for primary and secondary static text elements. These colors are applied to new labels dragged out in Interface Builder. The tertiaryLabelColor is for disabled static text elements, and quaternaryLabelColor is for large disabled static text elements. These colors can also be applied to other related UI elements where related and appropriate; for instance, quaternaryLabelColor is recommended for separator lines as well as large glyphs or icons.

These new colors as well as some of the existing system colors now paint differently depending on the current appearance. Please be sure to set colors while the appropriate appearance is in effect and do not cache their individual color component values.


Hyphenation

Hyphenation is now enabled by default for all text rendering and measurement. The hyphenation factor is 0.4.

In addition, the handling of the soft hyphen character (U+00AD) has been changed. In prior versions of OS X, we handled the character just as a line break opportunity when the hyphenation is disabled. Now, we always show the hyphen glyph whenever wrapping at the character.



Notes specific to OS X 10.9

Some of the major topics covered in this section include:



Sheet Presentation

Sheet API has been moved from NSApplication to NSWindow. In this move, a number of changes to the API have been made. First is the use of blocks as completion handlers, rather than delegation.

Rather than presenting a sheet:
    [NSApp beginSheet:mySheet modalForWindow:docWindow modalDelegate:nil didEndSelector:nil contextInfo:nil];
This will instead be:
    [docWindow beginSheet:mySheet completionHandler:nil];
Likewise, when handling the ending of a sheet, a separate method was needed to act as the endSelector:
    [NSApp beginSheet:mySheet modalForWindow:docWindow modalDelegate:self didEndSelector:@selector(didEndSheet:returnCode:contextInfo:) contextInfo:nil];
    - (void)didEndSheet:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo {
        [sheet orderOut:self];
        NSLog(@“Good bye sheet.”);
    }
This will instead be handled in the completionHandler block:
    [docWindow beginSheet:mySheet completionHandler:^(NSModalResponse response) {
        NSLog(@“Good bye sheet.”);
    }];
In this example, you’ll also notice that -orderOut: no longer needs to be called in the completion handler. If you do not dismiss the sheet, it will be done for you after the completion handler finishes.

NSModalResponse is a new typedef in NSApplication created with an enum of modal responses. NSModalResponseStop, NSModalResponseAbort, and NSModalResponseContinue are added in replacement of the deprecated NSRunStoppedResponse, NSRunAbortedResponse, and NSRunContinuesResponse.

NSWindow also adds two more modal responses: NSModalResponseOK and NSModalResponseCancel (which are replacements for NSPanel's NSOKButton and NSCancelButton).

A sheet's parent (the window or sheet it is attached to), can now be retrieved with -[NSWindow sheetParent]. This relationship is maintained from the time the sheet is begun with -beginSheet:… to when it is ordered out.

Another change brought by the moving of this API is queued and critical sheets. Previously, attempting to show a sheet on a window that already has a sheet would result in a 'Beep' to the user, a loss of contextInfo's memory, and no return call to the modalDelegate. The new NSWindow API will queue the second sheet if there is already a sheet present on the window. Once the first sheet is ended and ordered out, the second sheet will be brought down. Queued sheets can be ended ahead of time; so that if a queued sheet becomes unnecessary before the current sheet ends, the queued sheet doesn't have to be presented later. Critical sheets are sheets that are time sensitive and critical to the user; these will skip the queue and be presented on top of an existing sheet, if necessary. Sheets attempted to be presented while a critical sheet is up will be queued like normally; and after the critical sheet is dismissed, the previously presented sheet and queued sheets will be able to be interacted with again.

NSApplication's sheet API will continue to work as it did before, without the ability to queue sheets.


Alert dialogs

NSAlert's -beginSheetModalForWindow:modalDelegate:didEndSelector:contextInfo: has been deprecated in favor of -beginSheetModalForWindow:completionHandler:. Through its use of NSWindow's new sheet API, alerts with an alert style of NSCriticalAlertStyle will be presented as critical sheet.

NSAlertFirstButtonReturn, etc are marked as additional NSModalResponses used by -beginSheetModalForWindow:completionHandler: and -runModal. -[NSAlert runModal] is declared as returning an NSModalResponse (a typedef of NSInteger).

NSAlert's Functional API and -alertWithMessageText:defaultButton:alternateButton:otherButton:informativeTextWithFormat: has been deprecated. These creation methods have used different return codes from modern alert API; these old return codes (NSAlertDefaultReturn, NSAlertAlternateReturn, etc) are also deprecated. NSAlert and its properties should be used to create an alert instead.


Controls' -stringValue

NSSlider, NSStepper, and NSLevelIndicator use the set NSFormatter to format the result of -stringValue as well as retrieve the value set through -setStringValue:
If there is no set formatter, the value is formatted to an NSString with %g.


NSClipView

Before 10.9, overriding -constrainScrollPoint: aided in allowing developers to center (or use any custom positioning) a document within a scroll view. This works for constraining scrolling; however, constraining the changes resulting from an animation of a change in magnification requires knowledge of the size of the bounds. For this, NSClipView now has constrainBoundsRect:. This comes with the deprecation of -constrainScrollPoint:, as it can handle a superset of the problems that -constrainScrollPoint: could.



NSMatrix

The order of cells in NSMatrix is right-to-left layout when -[NSApplication userInterfaceLayoutDirection] returns NSUserInterfaceLayoutDirectionRightToLeft. This can be disabled or forced in IB by switching the Control's 'Mirror' value in IB.


NSPrinter

PPD access is deprecated through NSPrinter's table methods (-statusForTable:, -stringForKey:inTable:, etc). PMPrinter API should be used instead.


NSSlider

NSSliderCell exposes API to support appearance customization:
* -drawTickMarks is an override point to customize the drawing of tick marks.
* -barRectFlipped: returns the rectangle in which the slider bar is drawn.
* Overriding -drawBarInside:flipped: will actually override bar drawing.
* NSSliderCell's -knobRectFlipped: can be called directly if needed.


On apps linked against 10.9, the values returned by the dimensional methods (and passed into the drawing methods) are fitted to the size of default slider artwork. Any custom sliders should be sure to either override the dimensional methods with valid results for their custom artwork, or at the very least consider this fitting inside of -drawBarInside:flipped: and -drawKnobInside:flipped:. The dimensions returned by the default slider cell may also change in future releases, so they should not be assumed to remain constant. For binary compatibility, in apps linked before 10.9, NSSliderCell’s methods return and are passed the legacy, non-fitted rects.


Linear NSSliders now support right-to-left configuration when -[NSApplication userInterfaceLayoutDirection] returns NSUserInterfaceLayoutDirectionRightToLeft. This can be disabled or forced in IB by switching the Control's 'Mirror' value in IB.

NSSliderCell no longer receives an additional call to -continueTracking after the -stopTracking call.

NSSlider and NSSliderCell have formal deprecations for previously obsolete methods (-setImage:, -image, -setKnobThickness:, -setTitleCell:, -titleCell, -setTitleColor:, -titleColor, -setTitleFont:, -titleFont, -setTitle:, -title).


NSStackView

NSStackView is a new class in OS X 10.9. It is used to layout horizontal or vertical stacks of views using auto layout. Necessary constraints will automatically be created and modified when adding and removing views from a stack view to maintain a cohesive layout. This behavior is extended by customizing various properties of the stack view and the views it holds. Decreasing the clipping resistance priority allows the stack view to become smaller than the the minimum required to hold the provided views. Depending on the visibility priority associated with the internal views, they may either overflow and clip off the side, or drop from the view hierarchy. These dropped views are still retained by the stack view, and will be reattached if the stack view becomes the necessary size. Views can be forced to be dropped or reattached by setting the necessary visibility priority.

Note that NSStackView's hugging and clipping resistance priorities are distinct from NSView's contentHugging and compression resistance priorities. Since stack views have no intrinsic content sizes, contentHugging does not affect it. However, NSStackView's hugging priority is the priority at which the StackView wants its internal spacing to be at a minimum and "hug" its contained views. The clipping resistance priority is used to prevent the clipping of the contained views; a value less than NSLayoutPriorityRequired means the stack view can become less than the minimum size required to hold all of the its views.

Keep in mind that the default hugging priority of NSStackView is NSLayoutPriorityDefaultLow (250).  If you add views with hugging priorities of the same value, the constraints can be ambiguous, causing unexpected layouts such as oddly wide or tall views.  Fixing these issues can be as simple as tweaking the stack view’s hugging priority, the view’s content hugging priority, or by adding explicit size constraints on the view.

The view hierarchy that NSStackView manages is private. Additional subviews and constraints can be added to the stack view itself, but should not be added to its private views. These views should not be assumed to remain consistent in future releases, nor should they be assumed to be encoded or decoded with NSCoder. Because external constraints can be added to the views you add to a stack view, there should be no need to manipulate or measure these private views.



NSTabView

NSTabView uses the contentCompressionResistancePriority in the orientation of the tabs to prevent clipping of tabs. Top and Bottom tabs will use the horizontal contentCompressionResistancePriority; left and right tabs will use the vertical contentCompressionResistancePriority.


NSWindow

NSUnscaledWindowMask is formally deprecated.



Application and Window Occlusion

AppKit has a new API to notify an application if its windows are visible to the user on screen. If a window is not visible to the user then it is occluded.

There are two sets of methods; one set on NSApplication and one set on NSWindow. Both sets include a delegate method, an NSNotification, and a method to query the current state. To determine if any part of your application is visible, your application delegate can implement the method like this:
- (void)applicationDidChangeOcclusionState:(NSNotification *)notification
{
if ([NSApp occlusionState] & NSApplicationOcclusionStateVisible) {
// Visible
} else {
// Occluded
}
}
When the delegate method is called or the notification is posted, use either -[NSApplication occlusionState] or -[NSWindow occlusionState] to retrieve the current occlusion state of the application or window. Note that the result of this method is a bitfield, so the appropriate way to check for visibility is to use the bitwise-AND operator. Do not use the equality operator.

Windows are considered occluded if their entire content, including title bar and tool bar, is 100% covered by another opaque window. Windows are also occluded if they are ordered off screen, minimized to the dock, or on another space. Partial occlusion counts as “visible.” An application is only considered occluded if all windows owned by the application are occluded. That is, if any part of any window is visible, then the application is visible.

If your application has no windows except the menu bar, then your application is considered occluded. However, if your application uses an NSStatusItem, then the window that displays the status item is considered owned by your application and your application will not become occluded while the status item is visible.

This API can be used for increasing the performance of your application, including power, CPU, and network efficiency. For example, when your application is invisible to the user, it might cease expensive operations like retrieving data over the network or drawing an animation. You may also decide to trigger the start of expensive work when notified that the application or window has become visible.

The system reserves the right to delay notification of visibility during certain performance-critical periods. For example, exposing all windows on the system when the user enters Mission Control. In these cases the system will favor responsiveness to the user, and applications will be notified after the performance critical period has finished.



Auto Layout for NSViews in NSMenus

In 10.9, NSMenu has better support for views using auto layout. If the top-level view set on the menu item has translatesAutoresizingMaskIntoConstraints set to NO, the menu item will establish a required LeadingX constraint that position the view in the menu, and another required width constraint that sizes it equal to the menu. The height is the responsibility of the view.

If translatesAutoresizingMaskIntoConstraints is YES, the behavior is as it was in previous releases.

Auto Layout and window resize cursors

Window resize cursors now correctly reflect the minimum and maximum window sizes as determined by auto layout.

NSPopUpButtonCell cellSize

NSPopUpButton's cellSize method no longer considers the width of the key equivalent, which has never been drawn in OS X anyways.


View-based NSTableView scrolling optimized under Auto Layout

In 10.9, View-based NSTableViews have been optimized under auto layout to improve scrolling performance. To take advantage of the optimization, do not establish constraints that relate a view within an NSTableView row to a view outside of the NSTableView. (This would be difficult to do in any case - if you design your table view rows in IB you should be fine.)


NSApplication setActivationPolicy:

In 10.9, setActivationPolicy: now supports NSApplicationActivationPolicyAccessory.


NSWorkspace openURL:

In 10.9, -[NSWorkspace openURL:] may show an error dialog on failure, for apps linked using the 10.9 SDK or later. The return value of openURL: is unaffected.


NSWindow implicit animations

For apps compiled with the 10.9 SDK, -[NSWindow setFrame:display:] and -[NSWindow setFrameOrigin:] now perform animations, if invoked in an implicit animation context. To opt out, invoke -[NSWindow setFrame:display:animate:] and pass NO for the animate parameter.


Full screen NSToolbar changes

Before 10.9, NSToolbar would ignore the fullScreenAccessoryViewMinHeight when NSApplicationPresentationAutoHideToolbar is set. In 10.9, setting a fullScreenAccessoryViewMinHeight will cause it to be respected whether AutoHideToolbar is set or not. If you set a value of 0, the accessory view will animate in and out as the menu bar animates in or out.


Status Items with multiple menu bars

10.9 introduces multiple menu bars, each of which draws the status items. If your status item has a custom view, this view is positioned in one menu bar, and other menu bars get a “clone”, which looks identical. The clones are not exposed in the API.

The clones are drawn by redirecting your custom view’s drawing into another window. This means that your status item should not make assumptions about the drawing destination. For example, it should not assume that a call to drawRect: is destined for the view’s window, or that the resolution of the drawing destination matches the resolution of the status item’s screen. You must also not assume that the status item is on any particular display, except as described below.

The clones are only redrawn in NSDefaultRunLoopMode. This allows the status item to limit highlighting to one display, by driving the run loop in another mode, such as NSEventTrackingRunLoopMode. For example, if you wish to simulate a menu, you would implement mouseDown: to show your window, and run the run loop in NSEventTrackingRunLoopMode until you determine that the window should be dismissed. While the run loop is in this mode, only the true status item will redraw. Clone status items will not redraw, and therefore they will not show any highlight applied to the true status item.

When a clone status item is clicked, the clone exchanges locations with the true status item. This means that the location and screen of the status item window is reliable from within mouseDown:. You can access this information from your custom view, for example, using [[view window] screen] to position a window on the same screen as the status item.


NSSegmentedControl now better respects sendActionOn:

In 10.9, segmented controls that have sendActionOn: set to NSLeftMouseDownMask now work correctly.

constrainFrameRect:toScreen: now invoked for borderless windows

Prior to 10.9, the NSWindow method -[NSWindow constraintFrameRect:toScreen:] was invoked only for windows with NSTitledWindowMask set in their styleMask. In 10.9, this method is invoked for all windows. The default implementation does a more limited constraining for non-titled windows, as described in “NSWindows constrained to not intersect the menu bar” below.

NSWindows constrained to not intersect the menu bar

In 10.9, in support of the new multi-monitor architecture, windows are now constrained to not intersect the menu bar on their containing space. This restriction was already in place for titled windows, but it has been extended to borderless windows whose level is at least NSNormalWindowLevel but less than NSMainMenuWindowLevel. This behavior is implemented in -[NSWindow constraintFrameRect:toScreen:]. You may override that method in an NSWindow subclass to adjust or prevent this constraining.



NSNibLoading

The following nib loading methods on NSBundle and NSNib have been formally deprecated: +[NSBundle loadNibFile:externalNameTable:withZone:], +[NSBundle loadNibNamed:owner:], -[NSBundle loadNibFile:externalNameTable:withZone:], -[NSNib initWithContentsOfURL:], -[NSNib instantiateNibWithExternalNameTable:], and -[NSNib instantiateNibWithOwner:topLevelObjects:].

The ARC-compatible methods introduced in 10.8 should be used instead: -[NSBundle loadNibNamed:owner:topLevelObjects:], -[NSNib initWithNibData:bundle:], and -[NSNib instantiateWithOwner:topLevelObjects:].

It is important to note the difference in memory management between the deprecated and new methods. The deprecated methods retained the top level objects of the loaded nib file, requiring the caller to explicitly release them. This is no longer necessary with the new methods because they follow the standard Cocoa memory management rules and autorelease the top level objects. IBOutlet properties to top level objects should be strong (retain) to demonstrate ownership and prevent deallocation. Alternatively, one may hold a strong reference to the top level objects array, available as an out parameter on these methods.



Sharing Service

In 10.9, NSSharingService provides some new built-in services:
NSString * const NSSharingServiceNamePostOnTencentWeibo;
NSString * const NSSharingServiceNamePostOnLinkedIn;
NSString * const NSSharingServiceNameUseAsFacebookProfileImage;
NSString * const NSSharingServiceNameUseAsLinkedInProfileImage;
In addition NSSharingService provides the following new properties:
@property (copy) NSString *menuItemTitle;
@property (copy) NSArray *recipients;
@property (copy) NSString *subject;
@property (readonly, copy) NSString *messageBody;
@property (readonly, copy) NSURL *permanentLink;
@property (readonly, copy) NSString *accountName;
@property (readonly, copy) NSArray *attachmentFileURLs;


Responsive Scrolling

Mac OS 10.9 has a new feature called Responsive Scrolling. Responsive Scrolling allows the application to continue to rapidly scroll content even when the application’s main thread is busy doing other work. AppKit accomplishes this by having the document view draw more than what is currently visible during idle (see the Overdraw section in these release notes). The responsive scrolling thread is then free to replace what is on the screen with this previously drawn content. Responsive Scrolling requires one to use an NSScrollView, NSClipView and a document view.

By default, AppKit tries to turn on this feature where applicable. The following primary conditions, however, are not compatible with Responsive Scrolling. If any of the following conditions are met, the traditional scrolling behavior is performed.
* The application is primarily a Carbon application
* The documentView has an OpenGL context
* The window alpha is not 1.0
* The application links on 10.7 or prior (the application must link on Mountain Lion or higher to support this feature)


There are some secondary requirements that your NSScrollView subclass, NSClipView subclass, or document view must meet for them to be eligible for Responsive Scrolling. These secondary requirement checks may be bypassed by overriding the following new NSView class method on the view that fails the secondary requirements. You should strive to meet the requirements and only use this override as a last resort.
@implementation NSView
+ (BOOL)isCompatibleWithResponsiveScrolling;
@end
The list of secondary requirements are:
* Do not override -scrollWheel: in an NSScrollView, NSClipView subclass, or in the document view. (See the event modal notes in this section)
* Do not override -drawRect: in an NSScrollView subclass
* Do not override -lockFocus: in an NSScrollView, NSClipView subclass, or in the document view.

Layer backed secondary requirements:
* The root layer must be either the NSScrollView or an ancestor view

Traditional drawing secondary requirements:
* copiesOnScroll must be set to YES on the NSClipView
* The documentView must override -isOpaque and return YES

Event Modal
Traditionally, each scroll wheel event is uniquely hit tested and then handled. For non-gesture scrolling devices, this is still true. For gesture scrolling devices, this has changed dramatically. Once NSScrollView receives a scroll wheel event, it goes into a concurrent tracking loop. That is, future scroll wheel events are captured privately and processed on a background thread until the gesture, and any associated animation, is complete. If the user physically performs a consecutive scroll gesture, for responsive tracking purposes, it is considered a continuation of the current gesture and is therefore not hit tested.

You may be able to replace your NSScrollView, NSClipView subclass, or document view -scrollWheel: override with one or more of the following techniques.
* Register for bounds change notifications on the clip view
* Register for the LiveScrollNotifications (see the the ScrollView section)
If you only need to peek at the initial scroll wheel event, then return yes from +isCompatibleWithResponsiveScrolling to explicitly opt in to Responsive Scrolling.

While the scroll wheel events are being processed on a background thread, the main thread is periodically requested to synchronize. During this synchronization, the clip views bounds are updated and any required notification are posted. If the main thread is free, it is also asked to perform additional overdraw in the direction of the scroll (see NSScrollView - Overdraw). The result is that if the main thread is busy and / or cannot synchronize quickly enough, the visibleRect of the document may differ from what the user sees on screen. Also, if there is no existing overdraw content at the scrolled to location, then concurrently moving the content is paused while waiting for the main thread to catch up.

NSScrollView - LiveScrollNotifications

NSScrollView posts new notifications in response to user initiated scrolling. This may occur due to scroll wheels, scroll gestures, scroller tracking or page up / down animation. These notifications are sent on the main thread.
NSString * const NSScrollViewWillStartLiveScrollNotification;
NSString * const NSScrollViewDidLiveScrollNotification;
NSString * const NSScrollViewDidEndLiveScrollNotification;
If the user action has a known start and end point, the “WillStart” and “DidEnd” notifications are issued with 0 or more “Did” notifications sent in between. If the scroll is an animation (for example rubber banding), the “DidEnd” notification is not sent until the animation completes. If the scroll view is performing Responsive Scrolling, multiple consecutive scrolling gestures are grouped together into a single series of LiveScroll notifications bracketed by a single “WillStart” / “DidEnd” pair.

NSScrollView - Floating Subviews

Some subviews of the document view do not scroll with the rest of the document. Instead these views appear to float over the document (see NSTableView floating group rows). The following API makes it easier to work with these types of floating views. Also, NSScrollView ensures that any scrolling on the non-floating axis is visually performed synchronously with the document content. Note: You are responsible for keeping track of the floating views and removing them via -removeFromSuperview when they should no longer float. A view may only float on one axis at a time.
- (void)addFloatingSubview:(NSView *)view forAxis:(NSEventGestureAxis)axis;

NSScrollView - Overdraw

To facilitate Responsive Scrolling, your document view will be asked to draw portions that are not currently visible to the user. AppKit balances the amount of non-visible content drawn with the amount of memory and power usage such drawing requires. NSScrollView is then free to visually scroll to any previously overdrawn content during Responsive Scrolling.

If your document view has multiple subviews or you need more control over the overdraw area, your document view needs to implement the methods to ensure that all the appropriate content exists in the requested overdraw area.

The following method is called by NSView with a 'rect' for a recommended area that should be fully rendered for overdraw. Override this method and bring in additional subviews and pre-cached content for the 'rect' in order to perform responsive scrolling. Calling super may be required for some subclasses (such as NSTableView and NSOutlineView), so in general, super should always be called. To suppress overdraw for a particular view (such as NSTableView), override this method and call [super prepareContentInRect:[self visibleRect]].
- (void)prepareContentInRect:(NSRect)rect;
The preparedContentRect is the area of the NSView that has full content coverage. In general, this should be called with the area that is filled in fully with views. It should always include the visibleRect. Set this with a value equal to the visibleRect to have overdraw start from the visibleRect and automatically grow larger on idle, as is needed for optimal system performance.
@property NSRect preparedContentRect;


NSApplication

-[NSApplication stopModal] and -[NSApplication stopModalWithCode:] can now be called from an NSTimer or other runloop source. This lifts the restriction requiring abortModal to be used in these cases.

NSWindow styleMask

AppKit reserves the right to use all bits of the styleMask in NSWindow, and some are used for private communication with other Apple frameworks. Please do not use undocumented styleMask bits for your own NSWindow subclasses.


Spaces and Multiple Screens

In 10.9, we have added a feature where each screen gets its own set of spaces, and it is possible to switch between spaces on one screen without perturbing the spaces on the other screens. In this mode, a fullscreen window uses one screen, and leaves the contents of any other screens unchanged.

Each screen now has its own menu bar, and it is possible to show the Dock on any screen, provided you have the Dock set to “Position on Bottom”.

The menu bar has an active appearance on the active screen, which is typically the screen containing the key window. Menu bars on other screens have an inactive appearance.

In this mode, it is desirable for new windows to open on the active screen. In support of this model, +[NSScreen mainScreen] now returns the active screen, which is slightly different than its prior behavior of returning the screen containing the keyWindow, if any, and the zero screen otherwise.

A window restored at app launch through -restoreStateWithCoder: will return to its previous location, independent of active screen. A window positioned using -setFrameAutosaveName: will prefer the active display.

This feature can be disabled by unchecking the preference named “Displays have Separate Spaces” in the Mission Control preference pane in System Preferences. This setting only takes effect after logging out and back in, or restarting. NSScreen has API to query whether the separate space feature is enabled:
+ (BOOL)screensHaveSeparateSpaces NS_AVAILABLE_MAC(10_9);
When this feature is enabled, windows may not visibly span displays.  A window will get assigned to the display containing the majority of its geometry if programmatically positioned in a spanning position.  A window will get assigned to the display containing the mouse if the window is moved by the user.  A window clips to the edge of the display, whether or not there is another adjacent display.




Tagging Support in NSSavePanel

NSSavePanel provides a field that allows users to specify Tags (a new feature in OS X 10.9) that should be applied to the resulting file. However, since NSSavePanel isn't responsible for creating the file, your application should adopt new API to ensure the requested Tags are set correctly.

To opt in to NSSavePanel Tagging support, you should invoke -[NSSavePanel setShowsTagField:YES] prior to displaying the panel. When the user click Save in the panel, you can get the Tag names they entered by invoking -[NSSavePanel tagNames]. After creating the file at the requested URL, you should set the requested Tag names on the file by using the NSURLTagNamesKey API.

If your application does not adopt the above API, NSSavePanel will still show the Tags field and will attempt to automatically apply the Tags by listening to file system change notifications for a limited duration to detect when your application creates the requested file. However, this technique is imperfect, so you are strongly encouraged to test your application's support for tags in the save panel and adopt the above API if needed.



Export as PDF

In OS X 10.9, NSDocument and NSPrintOperation provide new API and functionality to aid you in creating an Export as PDF option that is consistent with the rest of the operating system.

NSDocument has a new standard IBAction method called -saveDocumentToPDF:. If your NSDocument subclass already implements -printOperationWithSettings:error:, then invoking this method will cause NSDocument to use the resulting NSPrintOperation to prompt the user for a location and save a PDF. The resulting PDF export panel will also include certain standard print panel configuration controls that you have enabled (like paper size and orientation) and the first accessory controller from the NSPrintOperation's NSPrintPanel.

The default implementation of -saveDocumentToPDF: simply invokes [self printDocumentWithSettings: @{ NSPrintJobDisposition : NSPrintSaveJob} showPrintPanel:NO delegate:nil didPrintSelector:NULL contextInfo:NULL]. When invoked with these parameters, the method will invoke -PDFPrintOperation instead of -printOperationWithSettings:error:. The default implementation simply invokes [self printOperationWithSettings:@{ NSPrintJobDisposition : NSPrintSaveJob } error:NULL], but you can override this method if you need to customize the way your application creates PDFs or to provide a different accessory controller.

If your application doesn't use NSDocument, you can still use NSPrintOperation to implement Export as PDF. Prior to OS X 10.9, running an NSPrintOperation that had its job disposition set to NSPrintSaveJob and its NSPrintJobSavingURL set to nil would result in undefined behavior. However, on OS X 10.9, doing this will cause NSPrintOperation to display an NSPDFPanel, prompting the user for a location where it will save the PDF.

Whether or not you use NSDocument, you can modify the PDF export panel used by NSPrintOperation by either creating a new NSPDFPanel with the desired options and accessory controller, or modifying the one that NSPrintOperation creates automatically.

If your application is unable to use NSPrintOperation to generate PDFs, you can still use NSPDFPanel to ensure your application's user interface is consistent with the rest of the operating system. In order to do this, you should first create an NSPDFInfo object, optionally changing the paperSize and orientation properties. Then you should invoke -[NSPDFPanel beginSheetWithPDFInfo:modalForWindow:completionHandler:] passing the NSPDFInfo object you created. When the completion handler is invoked, the given NSPDFInfo object will be modified with the URL, file extension hidden flag, and Tag names, and rendering parameters that should be used when creating the PDF.

Shoebox-like applications may wish to generate multiple separate PDFs when the user has selected multiple items. To support this, NSPDFPanel supports the NSPDFPanelRequestsParentDirectory option. When run with this option, NSPDFPanel will prompt the user to choose a directory instead of a directory and a document name. The URL of the resulting NSPDFInfo object will contain the user's chosen directory. You are responsible for appending a file name to this path.

If your application manually runs an NSPDFPanel but uses NSPrintOperation to create PDFs, NSPrintInfo provides -takeSettingsFromPDFInfo:, which will modify the receiving NSPrintInfo with all the settings from the given NSPDFInfo. But remember, if you use NSPDFPanelRequestsParentDirectory, you must modify the NSPDFPanel's URL by appending a file name before passing it to -takeSettingsFromPDFInfo:. If the URL doesn't looks like it points to a directory, the method will throw an exception.


Additional Use of -performActivityWithSynchronousWaiting:usingBlock: in NSDocument

NSDocument provides the -performActivityWithSynchronousWaiting:usingBlock: to ensure document concurrent operations are performed and their results presented in a properly serialized manner. Presentation of any alert or error sheet on a document is supposed to be done within an 'activity' block to avoid multiple sheets interfering with each other.

NSDocument internally presents many alerts on documents and is responsible for making sure this is done within an 'activity' block. However, prior to OS X 10.9, the alert that is displayed when the user edits a locked document was not presented within an 'activity' block. As a result, alerts originating from application-defined 'activities' could potentially interfere with it, often resulting in deadlocks. This has been fixed on OS X 10.9.


Bug Fixes for NSPathControl in Sandboxed Applications

Prior to OS X 10.9, NSPathControl behaved unexpectedly in sandboxed applications when used with a URL within the user's home directory. NSPathControl would fail to recognize that sandboxing redirects NSHomeDirectory() to the application's sandbox container. Additionally, the NSPathControl was given the URL to the user's real home directory, it would fail to recognize that path as home, and would therefore show the entire path up to the root of the volume instead of stopping at the user's home directory. These issues have been fixed on OS X 10.9.


NSSavePanel / NSOpenPanel

Key Value Observation compliance was dramatically increased for public and some private properties of actual, non sandboxed NSOpen and Save panels, including keys affecting other values. For example, if the directory value changes on a save panel, this will cause a KVO notification to be emitted for the URL value as well as the directory value. Sandboxed NSOpen and Save Panels do not have the same level of KVO compliance.


In the “On my Mac” mode of the App Centric Open Panel (the open panel shown for applications using iCloud), accessory Views are now hidden by default in and can be revealed by hitting the “Options…” button.


Specification of fonts in nib files

The name of the default system font has changed from "LucidaGrande" to ".LucidaGrandeUI".  In the vast majority of cases this should not present a problem.  However, there is a case where fonts can be unexpectedly decoded from an archive as "LucidaGrande" rather than the new system system font.  This can cause a variety of subtle issues, including slight changes to the layout of certain button titles.  This will occur if you are still using nib files rather than xib files, built them using Xcode 4 or earlier, and they use system fonts in non-standard point sizes. When you change the point size to be non-standard, older versions of Xcode will change the displayed font type from "System" to "Custom", and then it will not be decoded as the new system font on Mavericks. Xcode 5 will correct this problem when opening your nib file, so the UI will automatically show "System", but note that it's still necessary to save the changes.



NSSavePanel / NSOpenPanel

Automatic key loop recalculation is enabled. This not only obviates the need to explicitly recalculate the key loop after modifying a subview of the accessory view but also makes it possible for the accessory view itself to reliably declare itself a key view.



NSSound

Channel mapping is deprecated in 10.9, consequently channels should be mapped at a lower level using AudioUnitSetProperty.



Event-specific behavior of -isSwipeTrackingFromScrollEventsEnabled

In 10.9, the user may choose to have different preferences for the “Swipe between pages” behavior for mouse and trackpad input devices. It is now possible for this behavior to be enabled for trackpad devices but disabled for mouse devices (or vice versa). By default, swipe between pages is enabled for trackpads and disabled for mice.

AppKit provides the -isSwipeTrackingFromScrollEventsEnabled method to determine the current user preference. The behavior of this method is now based on the current event (as returned by [NSApp currentEvent]). If the current event originated from a mouse device, this method returns the user preference for mouse devices; otherwise, it returns the user preference for trackpad devices.

New Accessibility constants

These accessibility constants have been added:

— NSAccessibilityMarkedMisspelledTextAttribute

NSAccessibilityMisspelledTextAttribute was the original attribute to indicate misspelled text. In OS X 10.4, the Cocoa text system added support for NSAccessibilityMarkedMisspelledTextAttribute, which was used to indicate a word that was visibly marked as misspelled (for example, with a red squiggle underneath); the original MisspelledText attribute could also be used on text that was not visibly marked as misspelled (for example, a misspelled word that was currently being edited by the user).

Typically, a screen reader only wants to vocalize what a sighted user could see, and so the MarkedMisspelledText attribute was adopted by VoiceOver to provide feedback to the user about misspelled text. In OS X 10.9, VoiceOver has entirely stopped using the original MisspelledText attribute, and now only checks for MarkedMisspelledText.

When implementing accessibility for a custom text-editing engine, you should generally provide the MarkedMisspelledText attribute in order to support VoiceOver, especially in OS X 10.9 and later. You may optionally also support the MisspelledText attribute for compatibility with other accessibility clients.

— NSAccessibilityDescriptionListSubrole

This subrole is similar to the existing NSAccessibilityDefinitionListSubrole, but is preferred to represent HTML5 objects indicated by the <DL> tag.

Accessibility Notification support for custom accessible objects

The NSAccessibility informal protocol now supports a new protocol method, -accessibilityNotifiesWhenDestroyed.

Prior to 10.9, the only accessible objects that could post accessibility notifications were those that inherited from NSView, NSWindow, or NSCell. An application's custom accessible object, subclassed from NSObject, could not post notifications.

In 10.9 and later, an application's custom accessible object may post accessibility notifications if it follows the following guidelines:

– the object must implement -accessibilityNotifiesWhenDestroyed to return YES.

– the object must post the NSAccessibilityUIElementDestroyed notification at appropriate times, typically when the corresponding UI element in the application's visual interface is removed from the screen, and certainly when the accessible object is deallocated.

– the lifetime of the NSObject must match the lifetime of the corresponding element in the application's visual interface. It is common for a custom accessible object that acts as a proxy for an onscreen UI element to be autoreleased and deallocated very quickly, immediately after the application responds to a single accessibility request. This is not sufficient to support posting notifications, because any notification observers that are registered on the object will be removed as soon as the object is deallocated. Instead, the application must arrange for an accessible object that refers to a specific UI element to remain allocated as long as that UI element is visible.Accessibility protected content

The Accessibility API is designed to help make OS X more accessible to users with disabilities. To accomplish this, the API is able to vend all of the strings and values that are displayed onscreen to clients such as VoiceOver. This is critical, especially for book-reading applications, because it allows users who are blind to read and interact with the same content as everyone else.

However, some applications need to be able to prevent their string content from being copied by other applications that use the Accessibility API. It is now possible for an application to tell the Accessibility implementation that some of its content is protected.

There are two steps required to indicate that a particular UI element has protected content:

– use the NSAccessibilitySetMayContainProtectedContent API to indicate that this application contains protected content
– handle requests for NSAccessibilityContainsProtectedContentAttribute in your accessible objects’s -accessibilityAttributeValue: implementation, returning an NSNumber containing YES.

Accessibility API for transient UI

Application UI elements can appear, disappear, or change as a result of mouse movement to certain positions in the content, or other types of user input, such as press or release of a modifier key. This presents several problems for clients of the Accessibility API:

– there is no equivalent accessible way to simulate such mouse triggered events
– there's no way to know when/what happened as a result of mouse rollover

The Accessibility API now offers new features to support transient UI elements.

NSAccessibilityShowAlternateUIAction
NSAccessibilityShowDefaultUIAction
These accessibility actions should be implemented to present the alternative or default UI.

NSAccessibilityPostNotificationWithUserInfo
This API allows an accessibility notification to be posted with a user info dictionary. When transient UI elements are shown or hidden, an application should use this API to post NSAccessibilityLayoutChangedNotification with a user info dictionary containing a list of the UI elements that have changed.

NSAccessibilityLayoutChangedNotification
This notification lets accessibility clients such as VoiceOver know that some UI layout change has occurred. The client application then has the option to decide if it wants to give feedback, auto jump to a new UI, list the new or changed UIs in a menu, or do nothing. The notification can be used by anything that changes UI on screen. As an example, this could be triggered by an explicit NSAccessibilityShowAlternateUIAction, or by user input such as mouse hovering. Similarly, performing NSAccessibilityShowDefaultUIAction or mouse exiting a UI element to revert some transient UIs should also cause this notification to fire. The notification can contain a user info dictionary with the key NSAccessibilityUIElementsKey and an array of elements that have been added or changed as a result of this action.

NSAccessibilityAnnouncementRequestedNotification
This notification allows an application to request that an announcement be made to the user by an accessibility client such as VoiceOver. The notification requires a user info dictionary with the key NSAccessibilityAnnouncementKey and the announcement as a localized string. In addition, the key NSAccessibilityAnnouncementPriorityKey should also be used to help accessibility clients determine the important of this announcement. This notification should be posted for the application element.

NSAccessibilityUIElementsKey
This key is used in the user info dictionary for notifications. The value is an array of elements that are associated with the notification.

NSAccessibilityPriorityKey
This key can be used in the user info dictionary for any notification. This gives the client an opportunity to determine how to handle this notification based on the priority. For example, a developer can pass the priority for NSAccessibilityAnnouncementRequestedNotification. Clients such as VoiceOver can then decide to speak the announcement immediately or after the current speech is completed. The NSAccessibilityLayoutChangedNotification is another example where priority can help VoiceOver determine if the UI change requires the VO cursor to go to the new UI.

NSAccessibilityAnnouncementKey
This key is used in the user info dictionary for notifications. The value is a localized string. This should generally be used in conjunction with the NSAccessibilityPriorityKey to help accessibility clients determine the important of this announcement.

NSAccessibilitySharedFocusElementsAttribute
Returns an array of elements that also have keyboard focus when a given element has keyboard focus. A common usage of this attribute is to report that both a search text field and a list of resulting suggestions share keyboard focus because keyboard events can be handled by either UI element. In this example, the text field would be the first responder and it would report the list of suggestions as an element in the array returned for NSAccessibilitySharedFocusElementsAttribute.



NSAppearance

NSAppearance is a new class in Mac OS X 10.9. It can be used to access alternate appearances of standard system windows and views. You obtain an NSAppearance by name using +[NSAppearance appearanceNamed:]. A new appearance for controls that is appropriate for light backgrounds (such as popovers) is accessible via the name NSAppearanceNameLightContent. To access the default system NSAppearance, use the name NSAppearanceNameAqua.

NSAppearanceCustomization is a new protocol that NSView and NSWindow adopt that allows customization on those objects. To customize the appearance of a window, call setAppearance: on the window with your NSAppearance object. That will cause the window itself to take on the customizations in that NSAppearance, as well as any view in that window. To customize just a view, call setAppearance: on that view. Any specific customization not found in a view's appearance will fall back up to that view's superview, ultimately trying the window's appearance. If a customization is not found at the window level, the default (Aqua) appearance is used. Use the effectiveAppearance method (part of NSAppearanceCustomization) to access what NSAppearance object will be used when drawing that view or window; this takes into account appearances set on superviews and windows.


While drawing views, the currentAppearance is set for the drawing thread. To access the current appearance, use:
NSAppearance *currentAppearance = [NSAppearance currentAppearance];


Automatic Quote and Dash Substitution

Mac OS X 10.9 now contains global user preference settings for the use of automatic quote and dash substitution. Applications that provide for the entry of free-form text in which typographically correct quotation marks and other punctuation would be appropriate may follow these settings by using the new NSSpellChecker methods
+ (BOOL)isAutomaticQuoteSubstitutionEnabled;
+ (BOOL)isAutomaticDashSubstitutionEnabled;
and by listening to the following notifications to be notified of changes
NSString *NSSpellCheckerDidChangeAutomaticQuoteSubstitutionNotification;
NSString *NSSpellCheckerDidChangeAutomaticDashSubstitutionNotification;
For applications compiled on 10.9 and later, NSTextViews by default will automatically follow these settings, unless setAutomaticQuoteSubstitutionEnabled: or setAutomaticDashSubstitutionEnabled: has been called.





NSTableView/NSOutlineView General Updates

Prior to 10.9, deselecting a row with a cmd-click would call tableView:selectionIndexesForProposedSelection: but the resulting selection may not have been used. This has been properly fixed for applications that link on 10.9 and higher, and the resulting selection returned by the delegate will be used.

NSOutlineView now fully supports Right To Left language layout. This can be achieved in several ways. One can explicitly set the userInterfaceLayoutDirection in code or in a NIB. Or, if auto-localization is used and the app is linked on 10.9 (or higher), then the userInterfaceLayoutDirection will automatically be flipped if it differs from [NSApp userInterfaceLayoutDirection].

Prior to 10.9, calling moveRowAtIndex:toIndex: when the NSTableRowView being moved (or any subview of the NSTableRowView) was the first responder, would leave the table in a bad state. This has been fixed for all applications in 10.9. For applications that need to run on platforms prior to 10.9, it is recommended to first make the window the firstResponder before calling moveRowAtIndex:toIndex: (if the row being moved is the firstResponder).

Prior to 10.9 there was a visual glitch (specifically, a removed NSTableRowView) when performing a row delete right before a row insertion in the same beginUpdates/endUpdates block, but only when both animations where either NSTableViewAnimationSlideUp or NSTableViewAnimationSlideDown. This has been fixed for 10.9, and applications that need to target prior to 10.9 should ensure they do a different animation for the deletion, or perform the deletion in a separate beginUpdates/endUpdates block.

Using a View Based TableView with a rowSizeStyle of NSTableViewRowSizeStyleDefault will automatically update the rowSizeStyle of each cell view for tables with the NSTableViewHighlightStyleSourceList. However, prior to 10.9 the rowSize style for "header rows / group rows" would always be set to Medium and Large, when they should always be "small" regardless of the user setting in System Preferences. This has been fixed in 10.9 for all applications using a View Based TableView.

Using beginUpdates/endUpdates on a cell based tableview may potentially throw an exception "NSTableView Error: Insert/remove/move only works within a -beginUpdates/-endUpdates block." if the cell based table view is layer-backed. This has been fixed for all applications on 10.9 and higher. For prior applications, it is recommended to use a view based NSTableView when using beginUpdates/endUpdates, or to not layer-back the table view.

Calling [tableView addTableColumn:] after a call to [tableView moveColumn:toColumn:] may through an exception if done in the same call stack level; this has been fixed in 10.9 for all applications. For applications that need to work around this prior to 10.9, be sure to call addTableColumn: before calling moveColumn:toColumn:

Calling [outlineView removeItemsAtIndexes:inParent:withAnimation:] that results in removing an expanded item may have left the item retained by NSOutlineView for an indefinite amount of time. This has been fixed on 10.9. For applications that need to work around this prior to 10.9, call collapseItem: before removing the item.

Hiding and unhiding an NSTableColumn (via setHidden:) will cause the table to automatically resize other table columns to make room for the new table column (or take up slack for the one that was hidden). Previously, this would always attempt to resize columns based on the enclosingScrollView's visible width. On 10.9 this has been changed to prefer the actual width, in the case of a horizontally scrollable table view.

NSTableView has a user default to allow all the default animations it does to be slowed down: NSTableViewSlowMotion YES/NO, which can be set with 'defaults' or a command line parameter.

NSView - General Updates

NSView now exposes a property userInterfaceLayoutDirection, which is backwards available on 10.8 for NSView, and 10.7 for NSOutlineView. userInterfaceLayoutDirection defaults to [NSApp userInterfaceLayoutDirection]. It is up to a particular view's implementation to properly support Right To Left layout. NSOutlineView properly implements the Right To Left layout.


NSView - Layer-backed Views

NSView has some new API to ease layer-backed adoption. The new property canDrawSubviewsIntoLayer allows a parent view to draw all of its subviews into a single layer, when that parent view is layer-backed. This is also sometimes referred to as an “inclusive layer”, as all the children views are drawn inclusively into a single parent layer. Normally, calling setWantsLayer:YES on a parent view will create individual layers for that parent view and all individual subviews. However, each individual subview will not have wantsLayer==YES, but will inherit its own unique layer by virtue of being in a layer-tree. When canDrawSubviewsIntoLayer is set to YES, the parent view will draw all subviews into a single layer, and each individual subview will not have an individual layer. The exception is a particular subview which already has wantsLayer set to YES on it. It is recommended to first call setCanDrawSubviewsIntoLayer:YES, and then call setWantsLayer:YES to avoid unnecessary work. The reason to use canDrawSubviewsIntoLayer=YES, is when there is a view hierarchy which can not be refactored to take advantage of the new Mountain Lion 10.8 API of -wantsUpdateLayer=YES and -updateLayer. Another reason to use this feature is to collapse multiple layers into a single layer, in order to gain better application performance. It is generally recommended to turn canDrawSubviewsIntoLayer on only for parent views which are opaque; otherwise text font-smoothing may not look correct. However, it is acceptable to set canDrawSubviewsIntoLayer to YES for non-opaque views if no text is drawn, or if text is known to draw into some opaque portion of the view (or subview). Note that turning on canDrawSubviewsIntoLayer requires the layerContentsRedrawPolicy to not be NSViewLayerContentsRedrawNever; otherwise subview invalidation will not work.Please note that calling setLayer: with a custom layer will implicitly cause the layerContentsRedrawPolicy to be set to NSViewLayerContentsRedrawNever. This side effect is so AppKit will have a "hands off" approach on custom layers assigned to a view.

Please be aware that using an [NSAnimationContext beginGrouping / endGrouping] will cause a CATransaction to commit; this will cause layer-backed views to potentially get a -viewWillDraw (and a -drawRect: or -updateLayer) immediately after the [NSAnimationContext endGrouping] is called (or [CATransaction commit]).

Layer-backed NSButtons in 10.8 would previously not up-scale the image property, and would not properly use the alternate title when the state changed. Also, when a button was shown with no border (and just a title), the focus ring would not draw. NSButtonCell has been moved to properly use the NSView and NSCell focusRingMask* API. These bugs have been fixed for all applications on 10.9, and any applications providing (or hiding) the focus ring should use the focusRingMask* methods to provide (or customize) the focus ring.

In 10.8 MountainLion, layer-backed views would not invalidate the layer if the size was empty (0,0). This has been fixed for applications that link on 10.9 and higher.

Returning [NSNull null] from NSView's -animationForKey: or -defaultAnimationForKey: will now correctly be interpreted as not doing an animation. Previously, it would incorrectly cause the default CALayer animation to happen.

NSSplitView now overrides defaultAnimationForKey: and returns [NSNull null] for the "subviews" key. This suppresses the subviews animation, which is generally not desired and would be seen as a crossfade.

Layer backed views created by AppKit will now by default have the CALayer edgeAntialiasingMask property set to 0.

There is a new layerContentsRedrawPolicy of NSViewLayerContentsRedrawCrossfade. This can be used to do a crossfade of layer contents when the view's frame size changes. For some views, it also is applicable to views which have contents. For instance, one can easily cross fade the string of an NSTextField with:
  [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
context.allowsImplicitAnimation = YES;
textField.stringValue = @"Testing from the treehouse";
} completionHandler:nil];


Changes to layer rendering

Beginning in Mac OS X 10.9 CoreAnimation layer trees are rendered out-of-process. CoreImage filters attached to layers are not supported in this mode. If you are using CoreImage filters on a layer attached to NSView, please set the layerUsesCoreImageFilters property on your view to YES. When set, the layer tree hosting the NSView will be rendered in-process. Failure to set this property will result in an exception being thrown when filters are applied to a layer. Note that if you are setting filters using the NSView properties (backgroundFilters, compositingFilter, or contentsFilters) you do not need to set the layerUsesCoreImageFilters property.

Changes to the lifetime of named NSImages

Prior to Mac OS 10.9 images loaded through +[NSImage imageNamed:] were retained for the lifetime of the application. For applications linked on 10.9 and later this is no longer the case. Images loaded through +[NSImage imageNamed:] will still be cached for a brief time.

Changes to -[NSView allocateGState] and-[NSView releaseGState]

Beginning in Mac OS X 10.9 -[NSView allocateGState] and -[NSView releaseGState] are no ops. These methods were seldom used. Additionally, methods that relied on the side effects of these methods, specifically -[NSView gState] and -[NSWindow gState] will now always return 0. The method -[NSView renewGState] will continue to be invoked as it has in the past, when the view's location in the window has changed.

Changes to the default blend mode for block-based NSImages and NSImageRep subclassers

Beginning in Mac OS X 10.9, NSImage will invoke -[NSImageRep draw] with the current compositing operation set to NSCompositeSourceOver. This matches the behavior of drawing in NSView. Prior to this, -[NSImageRep draw] would be invoked with either the compositing operation passed to NSImage itself, or NSCompositeCopy, depending on the circumstances.
If you have subclassed NSImageRep, you may now depend on NSCompositeSourceOver being set when your -draw method is invoked. Likewise, if you are supplying a block to either +[NSImage imageWithSize:flipped:drawingHandler:] or -[NSCustomImageRep initWithSize: flipped:drawingHandler:] you may also depend on NSCompositeSourceOver being the current composite operation when your block is invoked.

Note that if you are deploying to previous OSes (or wish to use a non source-over composite operation) you should explicitly set the drawing operation. This can be done using the -[NSGraphicsContext setCompositeOperation:] API.

Fixes to layer:shouldInheritContentsScale:fromWindow

Prior to Mac OS X 10.9, returning YES from a layer delegate's layer:shouldInheritContentsScale:fromWindow: method would cause AppKit to update the contentsScale property of a CALayer, and then invoke setNeedsDisplay:YES on the NSView that contained that CALayer. In Mac OS X 10.9, the layer itself will be marked needing display. This fix is conditionalized against apps that have been linked on Mac OS X 10.9 or later.

Reminder about deprecated NSOpenGL functionality

The following NSOpenGL pixel format creation options should be considered deprecated, and have been deprecated by the underlying OpenGL libraries for some time. Their effects should be considered undefined, and their use avoided.
NSOpenGLPFAOffScreen
NSOpenGLPFAFullScreen
NSOpenGLPFASingleRenderer
NSOpenGLPFAWindow
NSOpenGLPFACompliant
NSOpenGLPFAPixelBuffer
NSOpenGLPFARemotePixelBuffer
NSOpenGLPFARobust
NSOpenGLPFAMPSafe
NSOpenGLPFAMultiScreen
The OpenGL library option NSOpenGLGOResetLibrary should also be considered deprecated, and its use avoided.

The following methods on NSOpenGLContext should also be considered deprecated. Note that support for these methods no longer exists for many hardware configurations, and their usage may result in crashes.
- (void)setFullScreen;
- (void)setOffScreen:(void *)baseaddr width:(GLsizei)width height:(GLsizei)height rowbytes:(GLint)rowbytes
- (void)copyAttributesFromContext:(NSOpenGLContext *)context withMask:(GLbitfield)mask
- (void)createTexture:(GLenum)target fromView:(NSView *)view internalFormat:(GLenum)format
When trying to create a full-screen context, use a fullscreen NSOpenGLView instead.
To render offscreen, please see the documentation regarding OpenGL FrameBufferObjects (FBOs) and glReadPixels.

Finally note that the entirety of the NSOpenGLPixelBuffer class should be considered deprecated. Use IOSurface in conjunction with GL framebuffer objects as a replacement.



NSColor

NSColor now provides three new methods for easier reuse of code that uses UIColor on iOS:
+ (NSColor *)colorWithWhite:(CGFloat)w alpha:(CGFloat)a;
+ (NSColor *)colorWithRed:(CGFloat)r green:(CGFloat)g blue:(CGFloat)b alpha:(CGFloat)a;
+ (NSColor *)colorWithHue:(CGFloat)h saturation:(CGFloat)s brightness:(CGFloat)b alpha:(CGFloat)a;
These create colors that are compatible with sRGB. However, where you have a choice, it's better to use the methods such as colorWithSRGBRed:green:blue:alpha: that specify the color space explicitly.



NSTokenField

There is a UI behavior change introduced for NSTokenField in Mac OS X 10.9. Adjacent Tokens are not longer visually connected when selected. As a dragging source, NSTokenField now removes the tokens drag/dropped with NSDragOperationGeneric (moving the selection).


NSTextField

Setting attributed placeholder string via -setPlaceholderAttributedString: renders the attributed string value while focused.



Notes specific to OS X 10.8

Some of the major topics covered in this section include:



NSDocument Support for iCloud

In 10.8, NSDocument-based applications with a ubiquity-container-identifiers entitlement gain new functionality and UI to facilitate iCloud document management.

When iCloud is enabled and an application is first launched or re-activated and no windows are visible or being restored, instead of creating a new Untitled document, NSDocumentController will display a non-modal open panel showing the user's iCloud library. From there an application can either open an existing document from iCloud or the local file system, or create a new document. To support this new non-modal open panel, NSDocumentController has added -beginOpenPanelWithCompletionHandler: and -beginOpenPanel:forTypes:completionHandler:. Note that currently the former method will only run the open panel non-modally when iCloud is enabled.

If your application overrides -[NSDocumentController openDocument:] and invokes -URLsFromRunningOpenPanel, you should switch to calling -beginOpenPanelWithCompletionHandler: instead.

If your application overrides -[NSDocumentController runModalOpenPanel:forTypes:] to customize the open panel, including adding an accessory view, you should also override -beginOpenPanel:forTypes:completionHandler: and do the same customization there. For compatibility NSDocumentController will continue to invoke the former if it is overridden when the latter isn't. As a result, the panel will be run modally instead of non-modally, giving your users a suboptimal experience.

iCloud-enabled applications also gain UI to facilitate moving documents into the cloud via the move and save panels. There is also a shortcut in the document titlebar menu to quickly move the document to iCloud. This menu item uses a new IBAction method on NSDocument: -moveDocumentToUbiquityContainer:. Also, as mentioned in the section on Drafts, new documents can get autosaved directly to the application's iCloud container, depending on the user's preference.

NSDocument also provides a new conflict resolution UI that allows users to inspect the contents of each conflict and save each conflicting version as a separate file, if they wish.

Applications that do not wish to use these features for any or all of their NSDocument subclasses can override +[NSDocument usesUbiquitousStorage] and return NO. If all of the application's declared NSDocument subclasses return NO from this method, then NSDocumentController will never show the new non-modal open panel.

NSDocument Versions Preservation Optimization

In Mac OS 10.7, when NSDocument decided that its file deserved to be preserved as a version prior to saving it would synchronously copy the file to perform the preservation. For significantly large files this could cause long hangs that interrupt the user's workflow. In applications linked on or after 10.8, NSDocument can avoid this hang by leveraging the 'backup' file that gets created during safe-saving.

When the current file's contents need to be turned into a version prior to saving, the file will get moved out of the way prior to the newly written file overwriting it. After the new file is successfully saved in the old file's place, a version can be created from the old file without requiring an expensive copy.

NSDocument uses -[NSDocument backupFileURL], a new method in 10.8, to control this behavior. This method only returns a URL when the current file needs to be preserved. When this method returns non-nil, -writeSafelyToURL:ofType:forSaveOperation:error: must ensure that the original contents of the file exist at that location prior to returning. Failing to do so is tantamount to data loss, since the user will be unable to revert to their previous versions. If your NSDocument subclass overrides -writeSafelyToURL:ofType:forSaveOperation:error: and doesn't call super, when you link against 10.8 you must ensure that your implementation obeys this rule. Alternatively, you can override -backupFileURL and return nil to disable this optimization. By doing so, -saveToURL:ofType:forSaveOperation:completionHandler: will fall back to the old synchronous copy technique. Applications that do saving in-place and don't use the safe-saving technique will almost always want to disable this optimization unless the cost of creating the 'backup' file is significantly less than a copy.

You should not override -backupFileURL to return a custom URL. Your override should either call super or return nil.

Sometimes versions are preserved after the new file is written, such as when the user chooses File > Save. In this scenario, the backup file optimization is not possible, so a copy is still necessary. However, for applications linked on 10.8, NSDocument will perform this copy on a background thread, leaving the main thread unblocked. To avoid corrupting these versions by modifying the file during this asynchronous copy, you should make sure that any direct access to your document's file is done with -performSynchronousFileAccessUsingBlock: or -performAsynchronousFileAccessUsingBlock:.


Debugging -performActivityWithSynchronousWaiting:usingBlock:, -performSynchronousFileAccessUsingBlock:, and -performAsynchronousFileAccessUsingBlock:

In Mac OS 10.7, NSDocument added these three APIs to ensure proper serialization of file access and user activity when using asynchronous saving. When an asynchronous activity or file access fails to properly invoke its completion handler, subsequent uses of these APIs wait forever. Unfortunately, due to the asynchronous nature of these APIs, the backtrace of these hangs usually doesn't provide enough information to debug the problem and identify the unterminated operation.

In 10.8, NSDocument provides a tool to help you more easily debug these problems. If your application is hanging in -performActivityWithSynchronousWaiting:usingBlock: or -performSynchronousFileAccessUsingBlock:, break in the debugger and execute this command:
po _NSDocumentSerializationInfo()
The output of this command will contain a listing of all unterminated invocations to these serialization APIs, including the document instance in question, the backtrace where the API was invoked, the type of serialization (file access vs. activity), and the current status (waiting for exclusive access vs. exclusive access is granted but block hasn't been executed yet vs. block is executing).

This function is intended for debug purposes only. It is not declared in any headers, and its name and output are subject to change at any time.


New and Updated NSDocument Operations

In 10.8, NSDocument has added some new document management operations and has enhanced others.

Users can now move and rename documents from within the application by using the Move To… and Rename… commands from the File menu or the document titlebar menu. The Move To… command shows the user a simple panel that allows the user to move the document to a new directory. The Rename… command causes the title in the window titlebar to become editable, allowing the user to change the title of the document. The new APIs controlling these operations are -renameDocument:, -moveDocument:, -moveDocumentWithCompletionHandler:, and -moveToURL:completionHandler:.

The Duplicate command has also been enhanced. Immediately after the duplicate document is created, the window's title will become editable, allowing the user to customize the title. If the user specifies a custom title, then the document will be saved into the same directory as the original document, if possible.

Certain documents that the system decides should not be edited, such as attachments from the Mail application, will be automatically duplicated when the user edits them to avoid modifying the original. This works by immediately causing the document to be autosaved to the ~/Library/Autosave Information directory with NSAutosaveElsewhereOperation. The autosavedContentsFileURL is set to that location and the fileURL is set to nil, so the document starts behaving like an unnamed duplicate document.

There is new API to query and control the "locked" state of the document. -isLocked returns YES when NSDocument thinks its file cannot be edited for reasons including, but not limited to, the "user immutable" flag being set, insufficient permissions, and -checkAutosavingSafetyAndReturnError: returning NO. You can attempt to unlock the document with the -unlockDocumentWithCompletionHandler: and -unlockWithCompletionHandler: APIs. NSDocument will attempt to unlock the file by clearing the "user immutable" flag and restoring write permissions. If that is not sufficient to unlock the file, or the file cannot be unlocked, then the operation will fail. You can attempt to lock the document with the -lockDocumentWithCompletionHandler: and -lockWithCompletionHandler: APIs. NSDocument will attempt to lock the file by setting the "user immutable" flag. If the file cannot be locked, then the operation will fail. There are two separate IBAction methods for unlocking and locking: -unlockDocument: and -lockDocument:. If you provide custom UI for these menu items, at validation time you should use -isLocked to decide which action should be used.

For applications adopting +autosavesInPlace, the Revert command has been broken up into multiple menu items that allow reverting to key versions without requiring the user to enter the Versions browser. These menu items continue to use the -revertDocumentToSaved: action and use the menu item's tag to identify which item the user selects. You should not attempt to modify these menu items in any way.

Finally, -browseDocumentVersions: is a new IBAction method on NSDocument that triggers its entry into the Versions browser.


NSDocument Drafts

In applications linked on or after 10.8, when a user edits an Untitled document in an iCloud-enabled application, NSDocument will automatically save it to the default ubiquity container as defined by [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil], unless the user has specifically disabled this. In this case, the document will be saved to ~/Library/Autosave Information as normal.

Once saved to iCloud, these documents behave very much like regular saved documents—they have a proxy icon in the title bar, they can accumulate versions, and so forth. However, when the user chooses to Save or Close the document, a save panel will be presented to allow the user to confirm the automatically chosen name and location, assign a new one, or even delete the file. Documents in this state are called "drafts". If the user does something prior to Save or Close to indicate that they want the document to be kept around, the document will no longer be considered a draft and hence will not show the save panel on Save or Close. Moving, renaming, or locking the file or editing it in another application are some examples of what can cause a document to stop being a draft. You can get and set the draft status of a document with the new -[NSDocument isDraft] and -[NSDocument setDraft:] APIs.

When a newly created document is saved as a draft, NSDocument invokes -setFileURL: without affecting the "Edited" status of the document, as shown in the titlebar. None of the NSSaveOperations in Mac OS 10.7 allow for this, so NSDocument in 10.8 defines a new save operation: NSAutosaveAsOperation. This new NSSaveOperation will be used by -autosaveWithImplicitCancellability:completionHandler: under specific circumstances. For example, a new unsaved document that has been changed with NSChangeDone will use NSAutosaveAsOperation instead of NSAutosaveElsewhereOperation. The URL that is used for the NSAutosaveAsOperation is determined internally by NSDocument and attempts to avoid name conflicts by appending a number to the document's display name that will be incremented until no conflict is found.

Some applications use -updateChangeCount: to cause NSDocument to autosave changes that don't originate directly from the user. For example, when importing a non-native document type, some applications create a new document with the imported contents and call -updateChangeCount: to ensure that the document gets autosaved with those contents. Many applications use NSChangeDone for this purpose. However, since the user did not explicitly cause this change, it is undesirable to turn this document into a draft. Applications should be careful to use the correct NSDocumentChangeType—in this case, NSChangeReadOtherContents—to prevent the conversion into a draft. Using NSChangeDiscardable will also prevent the creation of a draft.

When a document is scheduled to become a draft, the effective autosaving delay is greatly reduced to ensure that an autosave happens very soon after the first change. Once NSDocument has completed the NSAutosaveAsOperation, or if the operation has failed without any expectation of succeeding in the future, that NSDocument instance will no longer use NSAutosaveAsOperation on future autosaves. A document that has failed an NSAutosaveAsOperation will revert to behaving like a traditional Untitled document and autosaving will use NSAutosaveElsewhereOperation until the user gives the document a location via the save panel.

If one or more your application's NSDocument subclasses should not save untitled documents as drafts, you should override +[NSDocument autosavesDrafts] and return NO.


NSDocument Customizing Default Draft Names

In Mac OS 10.7, all newly created documents were called "Untitled" or "Untitled <number>" until the user gave them a title by saving. In 10.8, NSDocument will allow your application to replace "Untitled" with a custom string that is more descriptive for your application. For example, a word processing app may choose to automatically name documents "Résumé" when they’re created from a certain template, or a spreadsheet application may prefer new documents to be called "Spreadsheet" instead of "Untitled". You can do this in your application by overriding -[NSDocument defaultDraftName] and returning your custom localized string. If necessary, NSDocument will append a number to make the name unique.



CoreAnimation updates for NSView (i.e.: CALayer backed NSView)

For applications linked on 10.8 and higher, the following changes are in effect:

• NSTextField has been updated to allow LCD font smoothing to work when the view is layer-backed. Prior to 10.8, NSTextField would directly draw the text into the layer's contents; this would cause text to render incorrectly due to the LCD font smoothing algorithm not having adjacent pixels to smooth fonts with. Layer-backed applications that manually draw text should move to using NSTextField to get proper LCD font smoothing. One caveat is that NSTextField does require an ancestor which is layer-backed and opaque; it does not have to be the direct parent view, but some view in the ancestor chain must be opaque for this to be turned on and work correctly.

• For applications that link on 10.8, all layer-backed views may turn off LCD font smoothing to have text render better. Specifically, if a view returns NO from -isOpaque, then AppKit will turn off LCD-font smoothing before calling the view's drawRect: implementation. Otherwise, the drawing of text into a transparent layer will look incorrect (generally, it looks bolder and not smooth). However, there may be some specific cases where a layer-backed view knows it is manually drawing text into an opaque area. For these views, it is recommended that font smoothing be explicitly turned back on before drawing text. An example:
CGContextRef ctx = NSGraphicsContext.currentContext.graphicsPort;
CGContextSetShouldSmoothFonts(ctx, true);
[@"Tandem Unicycle" drawInRect: ... ];
• Prior to 10.8, calling setLayer: on NSView may not have properly updated the layer's position until a resize or reposition of the view happened; this has been fixed.

• Prior to 10.8, an AppKit managed layer would be destroyed (and removed) when a view was removed from a window or moved to another parent view. This would have the undesired effect of losing any custom properties set on the layer. For any view that explicitly has setWantsLayer:YES, the underlying AppKit managed layer will not be destroyed, and custom set layer properties will not get lost.

• Prior to 10.8, when AppKit removed the layer it managed, it would leave the layer's delegate set to the NSView that had the layer. For applications linked on 10.8 and higher, the delegate will be set to nil when it is removed (only if it is "owned" by AppKit). An application must re-assign the delegate to the view, if they save off and restore an AppKit owned layer (in general, this isn't recommended, and to get a layer to stick around one should call setWantsLayer:YES).
• Prior to 10.8, an AppKit managed layer would always have the layerContentsRedrawPolicy set to NSViewLayerContentsRedrawDuringViewResize when the layer was (lazily) created by AppKit. This prevented the value from being set at an earlier time before the layer was created. In 10.8, this is now done at view initialization time (either in -init or -initWithCoder). For views that host custom layers (via a call to setLayer:), the layerContentsRedrawPolicy will still be set to NSViewLayerContentsRedrawNever when setLayer: is called; it is assumed that the client wants to own the layer and control when it redraws. For all other regular NSView backing layers, it is required to properly set the layerContentsRedrawPolicy (usually in initWithFrame: or initWithCoder:). Prior to 10.8, the layerContentsRedrawPolicy was encoded in the NIB along with other properties of the view, despite there being no way to set it in Interface Builder. On 10.8, the layerContentsRedrawPolicy is no longer encoded in the NIB and should be explicitly set in code.

• Prior to 10.8, a flipped view would explicitly control a layer's position by updating it every call to setFrameSize:. However, this conflicts with allowing CoreAnimation to do frame size animations on a background thread without input from AppKit. To solve this, AppKit now controls the -geometryFlipped on the backing CALayer. Prior to 10.8, the anchorPoint was also set to be either (0,0) or (0,1) -- it varied depending on the superview being isFlipped or not. On 10.8, the layer's frame is now equal to the view's frame. The anchorPoint is also always set to be (0,0), since the positions are now equal. In order to properly control the flipped state of a layer, override -isFlipped on NSView.

• There are now two ways to provide a layer's contents when a view is layer-backed. The new preferred way is to implement -wantsUpdateLayer and return YES. When this returns YES, a new method called -updateLayer will be called. At this point, it is appropriate to directly set the view.layer.contents to an image (NSImage or CGImageRef) which can properly stretch (i.e.: a 3 part or 9 part image). To indicate how it should stretch use the CALayer contentsCenter property. If additional UI is needed to represent a particular control, add subviews (or sublayers) in -layout. -layout will be called for views that respond YES to wantsUpdateLayer, even if auto layout is not used. To get a new call to -updateLayer, invalidate the view with a setNeedsDisplay:YES. To get a new call to -layout, call setNeedsLayout:YES. Utilizing wantsUpdateLayer can lead to better performance when a view is layer-backed. Most of the standard AppKit controls will implement this to return YES if drawing methods are not subclassed and overridden. If a view returns NO from -wantsUpdateLayer, then the layer's contents will be filled in with whatever is drawn in drawRect:.

• As of 10.7, the way layer-backed views animate frame changes varies depending on the value of layerContentsRedrawPolicy. Animations are typically initiated using the animator proxy (i.e.: [[view animator] setFrame:]). If the layerContentsRedrawPolicy is NSViewLayerContentsRedrawDuringViewResize, then AppKit assumes the view needs to redraw on each step of the animation, and it will drive the animation on the main thread by calling setFrame: multiple times. If the layerContentsRedrawPolicy is NSViewLayerContentsRedrawOnSetNeedsDisplay, then AppKit will utilize Core Animation to drive the animation, which is done implicitly on a background thread, and the view will not get a setFrame: call for each step of the animation. Instead, Core Animation will stretch the layer's contents based on how properties are set on the CALayer. Note that using NSViewLayerContentsRedrawOnSetNeedsDisplay makes the view work just like a CALayer would for the animation; this means any property changes (which animate) will instantly appear at their final state as soon as the animation call is made. In other words the following happens:
view.layerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicyOnSetNeedsDisplay; // This should be set in init
NSRect frame = view.frame; // Starts out as 100, 100
frame.size = NSMakeSize(300, 300);
[view.animator setFrame:frame]; // Animates the view frame from 100,100 to 300,300
// However, reading back in the view.frame at this point will indicate it is already at 300,300

• For 10.8 and higher, the default value for the layerContentsRedrawPolicy varies on a control-by-control basis inside of AppKit. For a plain NSView, the value will be NSViewLayerContentsRedrawOnSetNeedsDisplay. For a custom NSView that overrides drawRect:, the default value will be NSViewLayerContentsRedrawDuringViewResize. When using -wantsUpdateLayer, it is important to always set the layerContentsRedrawPolicy (ideally to NSViewLayerContentsRedrawOnSetNeedsDisplay).This will allow the view to animate frame changes with Core Animation, as opposed to AppKit driving the animation on the main thread.

• On 10.8, AppKit will control the following properties on a CALayer (both when "layer-hosted" or "layer-backed"): geometryFlipped, bounds, frame (implied), position, anchorPoint, transform, shadow*, hidden, filters, and compositingFilter. geometryFlipped is only changed for apps that link on 10.8 and higher. Use the appropriate NSView cover methods to change these properties.

• When a layer-backed view is invalidated with setNeedsDisplay: (or setNeedsDisplayInRect:) the window is no longer invalidated. This allows just the view that needs to redraw to be redrawn, and no others. However, applications need to take care that they didn't accidentally depend on side effect drawing that previously happened due to a parent view invalidating its children views.

• When a view had the layerContentsRedrawPolicy set to NSViewLayerContentsRedrawOnSetNeedsDisplay, the view (and layer) may still have accidentally been invalidated on frame changes. This has been fixed for applications linked against 10.8, and when NSViewLayerContentsRedrawOnSetNeedsDisplay is set, the application must explicitly call setNeedsDisplay: on frame changes (if required).

• NSAnimationContext now has a new property, allowsImplicitAnimation, for layer-backed views. The default value is NO, and it is automatically set to YES when the -animator proxy is used. When YES, it allows any CoreAnimation animatable property to be animated. This allows for nested animations. In other words, doing a [[view animator] setFrame:frame] will animate the frame on 'view', but also any subviews also. Typically this is desired, as it allows the autoresizing of subviews to be done animated, and all the animations to be tied together in the same animation block with the same duration. If a subview has some particular property they don't want to animate, a new animation group can easily be created to disable this behavior. The converse is also true; if you want a particular property to always have a CoreAnimation animation, then -allowsImplicitAnimation can explicitly be set to YES. An example use:
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
     context.allowsImplicitAnimations = YES; // Enable implicit CoreAnimation animations
     // Any operations done in this block will be animated
} completionHandler:nil];
The use of allowsImplicitAnimation is very similar to the existing properties in UIKit on iOS: [UIView areAnimationsEnabled] and [UIView setAnimationsEnabled:]

•NSView's -cacheDisplayInRect:toBitmapImageRep: will now work properly with layer-backed views. For applications linked against 10.8, the layer will be drawn using CALayer's renderInContext:, allowing it to render all sublayers, including ones that may not have an associated view. This allows the use of -wantsUpdateLayer and -updateLayer: to work with -cacheDisplayInRect:toBitmapImageRep:.

• When using layer-backed views, Core Animation will animate a layer from its presentation state to whatever state you set on the layer (or view). However, sometimes animating a layer-backed view may not animate from the desired location or state. This can happen if your view (and implicitly the layer) never had a chance to display. For instance, consider this example:
NSRect frame = view.frame; // Starts at 0,0 -- the view was already drawn on screen at this location
frame.origin = NSMakePoint(100, 100);
view.frame = frame; // The view should move to 100,100 -- however, it has not drawn yet
frame.origin = NSMakePoint(300, 300);
[[view animator] setFrame:frame]; // The view should animate from point 100,100 to point 300,300
The desired animation is from point 100,100 to 300,300 - however, what may happen is the view will animate from point 0,0 to 300,300! This is because changes to view and layer trees are coalesced inside of NSAnimationContexts/CATransactions. Because it is impossible to know the outermost scoping of an animation context / transaction, changes may be coalesced even when not expressly desired. To handle these cases, each set of changes/animations you want to be visible should be isolated in their own animation grouping. This will cause the view/layer to render with the requested property change. For instance, this will work to enforce the first rendering to happen before the animation starts by chaining the actual animation to the end of the first animation group:
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
context.duration = 0;
NSRect frame = view.frame; // Starts at 0,0 -- the view was already drawn on screen at this location
frame.origin = NSMakePoint(100, 100);
view.frame = frame; // The view should move to 100,100 -- however, it has not drawn yet
} completionHandler:^ {
NSRect frame = view.frame; // Now it has drawn at 100,100
frame.origin = NSMakePoint(300, 300);
[[view animator] setFrame:frame]; // This will correctly animate from 100,100 to 300, 300 using the default animation context duration
}];

NSTableView/NSOutlineView

For a View Based NSTableView (or NSOutlineView), it has always been incorrect to acquire a view from the table inside the delegate method tableView:heightOfRow: (or outlineView:heightOfItem:). Now, the table will detect if either of these methods is called from inside the delegate method implementation and throw an exception (or log an error): viewAtColumn:row:makeIfNecessary: and rowViewAtRow:makeIfNecessary:.

NSControl now has new API to show "expansion tooltips". This is primarily available for expansion tooltips to be shown when using a View Based NSTableView. Call setAllowsExpansionToolTips:YES to allow them to be shown.

NSTableView now has a method for registering (or associating) additional NIBs for a View Based NSTableView called -registerNib:forIdentifier:. When one calls -makeViewWithIdentifier:owner: the identifier, first the table will look in its reuse queue for a view to reuse with that same identifier. If one is not found, it will then look for registered NIBs with that identifier. If a NIB is found, it is instantiated with the 'owner' passed to the method. All top-level views in the instantiated NIB are then placed in the reuse queue with their current identifier. For this reason, it is important to always set the identifier for all top-level views in a NIB that is registered with the table. The particular view with the requested 'identifier' is then returned from -makeViewWithIdentifier:owner:. For a particular identifier, if there are no available views for reuse, or no associated/registered NIBs (or none created at design time in IB), then the method -makeViewWithIdentifier:owner: will return nil. A single NIB can be registered multiple times with different identifiers; this should be done for each top-level view that is in the NIB. A corresponding method, -registeredNibsByIdentifier, will return an NSDictionary with all registered NIBs. The key in the dictionary will be the identifier, and the value will be the NIB that has been registered. To unregister a NIB, pass 'nil' in for the NIB in -registerNib:forIdentifier:.

NSOutlineView

The following methods now support being animated via the -animator proxy: -expandItem:, -expandItem:expandChildren:, -collapseItem:, and -collapseItem:collapseChildren:. As an example, to animate the expansion of a particular item: [[outlineView animator] expandItem:item];

Prior to 10.8, calling -reloadItem: (or -reloadItem:reloadChildren:) on a NSView Based NSOutlineView may not have reloaded the disclosure triangle button if the row changed from being expandable to not being expandable (or vice-versa).


NSButton / NSButtonCell

For applications linked on 10.8, NSButton and NSButtonCell now use the Lion API drawFocusRingMask and focusRingMaskBounds to do its focus ring drawing. Previously, calling setShowsFirstResponder:YES on NSButtonCell and manually drawing the cell would include the focus ring. On 10.8 this is no longer the case, the cell no longer explicitly draws the focus ring. To customize the focus ring, override NSButtonCell's implementation of drawFocusRingMaskWithFrame:inView:.

An NSButton configured as a radio button (with the -buttonType set to NSRadioButton), will now operate in a radio button group for applications linked on 10.8 and later. To have the button work in a radio group, use the same -action for each NSButton instance, and have the same superview for each button. When these conditions are met, checking one button (by changing the -state to 1), will uncheck all other buttons (by setting their -state to 0).

NSInterfaceStyle

NSInterfaceStyle is now deprecated. The methods have not been used in AppKit in a while.

All the "mnemonic" set of methods are now deprecated. IE, in NSButtonCell: setTitleWithMnemonic:, setAlternateTitleWithMnemonic:, setAlternateMnemonicLocation:, alternateMnemonicLocation, and alternateMnemonic. The methods that take a title will still call setTitle: with the ampersand stripped from the parameter. Under MacOS, these methods have historically not been used and did nothing.



Zooming ScrollView

NSScrollView now has built-in magnification support. You must opt-in by setting the allowsMagnification property to YES. When the user performs a pinch gesture, NSScrollView will magnify, centering around the mouse location. When the user performs a smart zoom gesture (2-finger double tap on trackpads), NSScrollView will attempt to intelligently magnify the content under the cursor. However, NSScrollView needs help from your document view to determine your content layout. See the Smart Zoom section below for more details.
/* Allow the user to magnify the scrollview. */
@property BOOL allowsMagnification;
/* This value determines how much the content is currently scaled. To animate the magnification, use the object's animator.
The default value is 1.0.
*/
@property CGFloat magnification;
/* This value determines how large the content can be magnified. It must be greater than or equal to the minimum magnification.
The default value is 4.0.
*/
@property CGFloat maxMagnification;
/* This value determines how small the content can be magnified. The default value is 0.25.
*/
@property CGFloat minMagnification;
/* Magnify content view proportionally such that the entire rect (in content view space) fits centered in the scroll view.
The resulting magnification value is clipped to the minMagnification and maxMagnification values. To animate the magnification,
use the object's animator.
*/
- (void)magnifyToFitRect:(NSRect)rect;
/* Scale the content view such that the passed in point (in content view space) remains at the same screen location once the scaling
is completed. The resulting magnification value is clipped to the minMagnification and maxMagnification values. To animate the
magnification, use the object's animator.
*/
- (void)setMagnification:(CGFloat)magnification centeredAtPoint:(NSPoint)point;
The magnification property is observable. There are also notifications that will inform you when the magnification property is being changed due to user action. This may be due to the user performing a pinch gesture or a smart zoom gesture. When animating the magnification value yourself via the object's animator, these notifications are not sent.
/* This notification is sent at the beginning of a magnify gesture. The notification object is the scroll view performing the magnification.
*/
NSString *NSScrollViewWillStartLiveMagnifyNotification;
/* This notification is sent at the end of magnify gesture. The notification object is the scroll view view performing the magnification.
*/
NSString *NSScrollViewDidEndLiveMagnifyNotification;

Smart Magnification

There is a new NSEvent type for the smart zoom gesture (2-finger double tap on trackpads) along with a corresponding NSResponder method. In response to this event, you should intelligently magnify the content.
NSEventTypeSmartMagnify
- (void)smartMagnifyWithEvent:(NSEvent *)event;
NSEventTypeSmartMagnify is limited to 64 bit only.

Better yet, let NSScrollView perform the intelligence for you. In your NSScrollView document view, implement the following method to provide NSScrollView with semantic layout information of your content.
/* Return the complete rect of the most appropriate content grouping at the specified location. For example, if your content
is divided into three columns, return the entire rect of the column that contains the location. NSScrollView will attempt
to magnify such that the smaller dimension fits inside the scroll view while remaining within the
minMagnification, maxMagnification range.
   If your content layout is sub-divided further than one level deep (for example, two boxes that each contain multiple text
boxes), then use the visibleRect parameter to determine when to provide the rect of a sub-grouping. Always return a rect
for the appropriate grouping. If there is no deeper content grouping, return the rect for the deepest grouping. NSScrollView
will determine when to pan, magnify in, and magnify out.
   Return NSZeroRect for the default behavior.
*/
- (NSRect)rectForSmartMagnificationAtPoint:(NSPoint)location inRect:(NSRect)visibleRect;


Quick Look Gesture

There is now API to receive the Quick Look gesture (also known as the dictionary look up gesture). The user can perform this gesture with a three finger single tap, or the appropriate keyboard shortcut (Cmd-Ctl-D by default). There are two new NSResponder methods: an event method and an action method.
/* Perform a Quick Look on the content at location in the event. If there are no Quick Look items at the location, call super.
Also, see quickLookPreviewItems: further below.
*/
- (void)quickLookWithEvent:(NSEvent *)event;
/* Perform a Quick Look on the text cursor position, selection, or whatever is appropriate for your view. If there are no Quick Look
items, then call [[self nextResponder] tryToPerform:_cmd with:sender]; to pass the request up the responder chain. Eventually
AppKit will attempt to perform a dictionary look up. Also see quickLookWithEvent: above.
*/
- (void)quickLookPreviewItems:(id)sender;
To support the new event responder method, there is also a new NSEventType, NSEventTypeQuickLook. The only valid properties of and NSEventTypeQuickLook event are: -locationInWindow and -modifiers. A quick look event does not come in through the normal event mechanism, therefore there is no corresponding event mask for it, nor should you attempt to look for it in sendEvent: or with nextEventMatchingMask:… methods.

NOTE: NSApplication's default implementation of quickLookPreviewItems:, will perform a dictionary lookup. NOTE: There is a bug that causes the quickLoop responder methods to jump from NSWindow directly to NSApp bypassing NSWindowController, NSDocument, and NSAppDelegate.


NSPageController

NSPageController is a new class in 10.8 used for controlling swipe navigation and animations between views or view content.  It is useful for user interfaces which control multiple pages as in a book or a web browser history. NSPageController has a delegate that can be used to manage a predefined array of content via NSViewControllers, or used to manage a history of content snapshots built up due to user navigation.

NSPageController inherits from NSViewController. You must assign the view property to a view in your view hierarchy. NSPageController does not vend a view. NSPageController does insert itself into the responder chain.

Conceptually, NSPageController manages swiping between an array of pages (arrangedObjects). Using the selectedIndex, you can determine how many pages forward or backward the user may navigate.

There are two modes that NSPageController may operate in, History and Custom. The main difference between the two modes is that History mode expects pageController.view to be the content and Custom mode expects pageController.view to be be a container for the content that you will supply by returning viewControllers in your delegate methods.

NSPageController History Mode aka Non View Controller Mode

History mode is designed to be the easiest way to create a history UI. NSPageController will manage the history (arrangedObjects), snapshots and user navigation between pages in the history.

As the user navigates to new content, add to the history by calling navigateForwardToObject:. NSPageController will remove any arrangedObjects after the selectedIndex and then add object to the end of the arrangedObjects (and update the selectedIndex). Just like navigating in a new direction in a web browser, all forward history is lost once the user starts navigating a new path. After returning from navigateForwardToObject: you are free to update the contents of pageController.view.

During swiping, the following optional delegate methods are called in the following order:
- (void)pageControllerWillStartLiveTransition:(NSPageController *)pageController;
This is a good time to stash information that you need to restore, such a scroll positions. After returning from the above delegate method, pageController.view is hidden. In its place NSPageController shows a private view hierarchy to animate previously taken snapshots of the page history. This allows NSPageController to remain responsive to the user without any work on your part.
- (void)pageController:(NSPageController *)pageController didTransitionToObject:(id)object;
Called after a physically successful swipe, but before the animation has completed. The supplied object is the page the user navigated to -- the new selectedIndex object in arrangedObjects. If you need to start some background loading tasks, now is the time to do it, however, do not block the main thread or the animation will stutter or pause.
- (void)pageControllerDidEndLiveTransition:(NSPageController *)pageController;
The swipe and all animations are completed. Restore any scrolls setting or anything else you need to do. The pageController.view is still hidden at this point and you must call -completeTransition on NSPageController to tell NSPageController to hide the private transition view and show pageController.view. Often you do this immediately, however, if your content is not ready you can call this at a later date. See "Completing the Transition" below.

NSPageController Custom Mode aka View Controller Mode

Custom mode is designed to give you more control over the swiping process and to facilitate more UI designs than just history. You can even use custom mode to create a history UI. In this mode, pageController.view is a container view and the content views are vended by viewControllers supplied by your delegate. (Tip: Draw your background in this view.) To enable custom mode, you must implement the following two methods in your delegate:
- (NSString *)pageController:(NSPageController *)pageController identifierForObject:(id)object;
- (NSViewController *)pageController:(NSPageController *)pageController viewControllerForIdentifier:(NSString *)identifier;
NSPageController caches the view controllers supplied for each identifier and only asks its delegate to create more if one does not already exists in its cache (this is very similar to how view based NSTableViews work.) If you have different types of views you want to swipe in, then supply a different identifier for each type.

When needed, you will be asked to prepare a viewController with a page via the following optional delegate method. If you do not implement this method, then the representedObject of viewController is set to object.
- (void)pageController:(NSPageController *)pageController prepareViewController:(NSViewController *)viewController withObject:(id)object;
You will be asked to prepare a viewController with a nil object for each unique identifier it encounters. NSPageController will use this to generate a default snapshot for that identifier.

Generally, when using custom mode, the set of pages are known and it is your responsibility to set the arrangedObjects and initial selectedIndex.

During swiping, the following optional delegate methods are called int the following order:
- (void)pageControllerWillStartLiveTransition:(NSPageController *)pageController;
This is a good time to stash information that you need to restore, such a scroll positions. After returning from the above delegate method, NSPageController takes a snapshot of the selectedViewController.view and then removes it from pageController.view. NSPageController replaces it with a private view hierarchy to animate previously taken snapshots. Unlike when building up a history, snapshots may not yet exist for the page being navigated to. In this case, a previously gathered default snapshot is used for that page's identifier. Regardless if using a default snapshot, or a previously gathered snapshot of actual contents, a viewController is prepared for the page being navigated to. This viewController.view is then asked to draw on a background thread while swiping continues (note, the view is currently windowless). Once the background threaded drawing completes, the initial snapshot is replaced with the newly generated snapshot.
 - (void)pageController:(NSPageController *)pageController didTransitionToObject:(id)object;
Called after a physically successful swipe, but before the animation has completed. The supplied object is the page the user navigated to -- the new selectedIndex object in arrangedObjects. Important, the pageController.selectedViewController has not been updated yet. In custom mode, this delegate method isn't all that interesting, however, If you need to start some background loading tasks, now is the time to do it. Do not block the main thread or the animation will stutter or pause.
- (void)pageControllerDidEndLiveTransition:(NSPageController *)pageController;
The swipe and all swipe animations are completed. The selectedViewController.view is still detached at this point and you must call -completeTransition on NSPageController to tell NSPageController to hide the private transition view and update the selectedViewController. Often you do this immediately, however, if your content is not ready you can call this at a later date. See "Completing the Transition" below.

NSPageController Completing the Transition

As discussed above, NSPageController uses a private view hierarchy during swiping. To create a seamless transition to the new content, it is your responsibility to inform NSPageController when you are ready to draw the new content. Ideally, the new content should match the snapshot and the user is none the wiser. You tell NSPageController to complete the transition by calling -completeTransition. If needed, a viewController is prepared and then the contentView is shown (or added) to the view hierarchy and the private transition view is hidden.

During NSPageController initiated animations, -pageControllerWillStartLiveTransition and -pageControllerDidEndLiveTransition are called on the delegate. Generally during pageControllerDidEndLiveTransition you will call -completeTransition. Programatic animations via the animator proxy do not call the delegate methods and you are responsible for calling -completeTransition when the animation completes.This is easily done via a completion handler on an NSAnimationContext grouping. (see below)

To instantly change the selectedIndex:
  pageController.selectedIndex = newIndex;
To animate a selectedIndex change:
  [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
[[pageController animator] setSelectedIndex:newIndex];
} completionHandler:^{
[pageController completeTransition];
}];

NSPageController Transition Styles

There are three transition animation styles. These transition styles are independent of the delegate mode. It is perfectly reasonable to create a history style UI using the viewController (custom mode) delegate methods. Simply set the transition style appropriately.

NSPageControllerTransitionStyleStackHistory - Pages are stacked on top of each other. Pages animate out to the right to reveal the previous page. Next pages animate in from the right. (See Safari as an example)

NSPageControllerTransitionStyleStackBook - Pages are stacked on top of each other. Pages animate out to the left to reveal the next page. Previous pages animate in from the left. (See Preview as an example)

NSPageControllerTransitionStyleHorizontalStrip - Pages are laid out next to each other in one long horizontal strip

The best way to think about the two stack transition styles is to think about the way the pages are stacked on top of each other. In a Book, page 1 is first. Page 2 and subsequent pages are stacked underneath page one. When navigating forward, the user swipes the current page out to reveal the next page. When navigating backward, the user swipes the previous page in and on top of the current page. In History, the pages are stacked over time in reverse order. That is, page 2 is stacked on top of page 1 and page 3 is stacked on top of page 2, etc… When navigating backward, the user swipes the current page out to reveal the previous page. When navigating forward, the user swipes the next page in and on top of the current page.

NSPageController Layer Backed Mode

When using the Custom mode, if pageController.view is layer backed, live layers are used during transition instead of snapshots.

NSPageController Notes

NSTableView is not thread safe! Do not tell NSTableView to reload its data while it is drawing on a second thread or it will crash. When using history mode, do not wire pageController.view to an NSSplitView subview. This will actually cause a 3rd split when the private transition view is put in the view hierarchy. You can work around this by using an empty NSView as the NSSplitView subview and placing the real contents in a subview of the empty view.


Smooth Scrolling

Smooth scrolling has been removed from user preferences. A consequence of this is that the default name has changed. Any use of @"AppleScrollAnimationEnabled" should be replaced with @"NSScrollAnimationEnabled". If you need to determine the default state of smooth scrolling, the following code will return the correct BOOL value
  [[NSUserDefaults standardUserDefaults] boolForKey:@"NSScrollAnimationEnabled"];

Accelerated Scrolling

Similar to iOS, on the third consecutive fast scroll gesture, the scrollingDelta of the scrollWheel event is automatically accelerated until either the user takes too long between physical scrollWheel gestures or the user starts to scroll slowly during another accelerated scrollWheel gesture.



Changes in Loading Nib Files

To support new features in localization, some nib loading paths in AppKit no longer use the deprecated loadNibFile:externalNameTable:withZone: method. If your application uses certain alternative localization techniques that depend on this method being called, and is linked with the Mountain Lion SDK or later, then localized resources may not be loaded correctly. You should switch to the new localization features that are part of Mountain Lion.



Auto Layout View Priorities

In 10.8, the NSView methods setContentHuggingPriority:forOrientation: and setContentCompressionResistancePriority:forOrientation: now raise an exception if the priority is zero or less, or more than NSLayoutPriorityRequired. In 10.7 and earlier, these values were silently accepted but could’ve later led to a crash.

Auto Layout NSSplitView improvements

In 10.8, NSSplitView properly respects constraints applied to its subviews, such as their minimum view widths. There are also new APIs for controlling the holding priorities, which determine both the NSLayoutPriority at which a split view holds its sizes and also which views change size if the split view itself grows or shrinks.
- (NSLayoutPriority)holdingPriorityForSubviewAtIndex:(NSInteger)subviewIndex;
- (void)setHoldingPriority:(NSLayoutPriority)priority forSubviewAtIndex:(NSInteger)subviewIndex;
In order to take advantage of these improvements, you must NOT implement any of the following NSSplitViewDelegate methods:
splitView:constrainMinCoordinate:ofSubviewAt:
splitView:constrainMaxCoordinate:ofSubviewAt:
splitView:resizeSubviewsWithOldSize:
splitView:shouldAdjustSizeOfSubview:
These methods are incompatible with auto layout. You can typically achieve their effects and more with auto layout.

Auto Layout NSTextField wrapping improvements

In 10.8, NSTextField has some new APIs to allow better support for wrapping text fields under auto layout.
- (void)setPreferredMaxLayoutWidth:(CGFloat)width;
- (CGFloat)preferredMaxLayoutWidth;
When you ask a wrapping text field for its size, by default it lays out as if it has infinite width available, i.e. in one long line (assuming it has no line break characters). Its intrinsicContentSize is the same: wide and short. However, if you set a preferred maximum layout width, the text field then measures itself as if it were confined to a rect of that width (and infinite height). Under auto layout, assuming no other constraints determine its size, its width will not exceed its preferred max, and its height will be sufficient to show all the text contents.

A common pattern is to have a wrapping NSTextField whose width is some constant determined by other constraints, and whose height should be sufficient to show the full text at that width. That can be achieved with the following pattern:
[[textField window] layoutIfNeeded];
[textField setPreferredMaxLayoutWidth:[textField alignmentRectForFrame:[textField frame]].width];
This works as long as the text field view width is not dynamic.

Auto Layout NSControl alignment rects

In Lion, the alignment rects, baselines, and intrinsic content sizes reported by many controls were slightly off. In 10.8, these have been corrected. In particular, NSPopUpButton has been modified to report an intrinsicContentSize with significantly less extra padding.

AppKit has historically resisted changing a control's reported cellSize for binary compatibility reasons, even if the underlying artwork changes. The intrinsicContentSize is intended to always be correct, and can be used as a "better sizeToFit" even when not using auto layout, like so:
  NSRect alignmentFrame = (NSRect){NSZeroPoint, [control intrinsicContentSize]};
[control setFrame:[control frameForAlignmentRect:alignmentFrame]];

Be aware that this is only sensible for controls that have both a natural width and height, like NSButtons. Controls that are fully flexible (such as NSSlider) will report NSViewNoIntrinsicMetric for their width and/or height, and you should set those dimensions explicitly.

Auto Layout and Non-Finite Frames

Under auto layout in 10.7, if a view returns YES from translatesAutoresizingMaskToConstraints and that view has a non-finite frame size or origin (such as infinity or NaN), an exception would be raised when creating the corresponding constraints. When not using auto layout, the frame has historically been silently tolerated (though the view would not appear). In 10.8, auto layout now logs a warning and flushes all non-finite frames to zero, for better compatibility with the non-auto layout behavior.

Of course, all non-finite view frames are bugs. To assist in tracking these down, a new user default NSViewRaiseOnInvalidFrames is provided. If this is set to YES, then both setFrameSize: and setFrameOrigin: (and by extension, setFrameSize:) will raise an exception if their parameters are non-finite.



NSSharingService

NSSharingService is a new class in 10.8 that can be used to share items to different kinds of local and remote services. Items are objects which respond to the NSPasteboardWriting protocol, like NSURL, NSImage or NSString. Please refer to the interface in <AppKit/NSSharingService.h> for the API.

If an NSURL is a file URL (pointing to a video for example), then the content of the file will be shared. If the URL is remote, then the URL itself will be shared.


Sharing service integration for NSTextView

The default NSTextView contextual menu contains sharing service items relevant for the current selection.

In addition to the contextual menu support, -[NSTextView orderFrontSharingServicePicker:] action method provides support for the sharing service picker facility provided by NSSharingService. A new NSTextViewDelegate method, -textView:willShowSharingServicePicker:forItems:, can be implemented by the delegate to further customize the picker behavior using NSSharingServicePicker.


ARC Weak References

Starting in 10.8, instances of NSWindow, NSWindowController, and NSViewController can be pointed to by ARC weak references.


NSApplication

If an application is launched because a user selected a notification in the Notification Center, NSApplicationLaunchUserNotificationKey will be present in the userInfo dictionary of NSApplicationDidFinishLaunchingNotification. Its value is an NSUserNotification object.
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
NSUserNotification *launchNotification = [[notification userInfo]
objectForKey:NSApplicationLaunchUserNotificationKey];
if (launchNotification) {
// application was launched by a user selection from Notification Center
}
}
NSApplicationLaunchUserNotificationKey has replaced NSApplicationRemoteNotificationKey, which was introduced in Lion but is deprecated in Mountain Lion.


Full Screen

We now allow a fullscreen window to occupy an external display. This allows users to specify which display should contain the fullscreen window by first moving the non-fullscreen window to the desired display. When a fullscreen window is on an external display, other displays are covered in linen shield windows, as before. The menu bar can be shown by mousing up to the top of the external display. The Dock is autohidden, and remains on whatever display edge is specified in user preferences. If your application implements a custom fullscreen transition, using window:startCustomAnimationToEnterFullScreenWithDuration:, you should choose the destination screen for the fullscreen window by finding the screen containing the majority of the window prior to the transition.

Much of the underlying Spaces architecture has changed in 10.8. This should have no effect on your application if you are using the NSWorkspace and NSWindow API, but you may notice changes if you have assumptions about timing of when the current space changes during a fullscreen transition, for example.



Using NSSavePanel / NSOpenPanel API in an App Sandbox

When you enable app sandboxing for your application (by checking "Enable App Sandboxing" for a target in Xcode), any calls to NSSavePanel and NSOpenPanel objects are redirected to a separate process which displays the Save/Open panel. This process is pboxd (aka "Powerbox").

Sandboxed NSSavePanel and NSOpenPanels were introduced in Lion. There are no new API changes in Mountain Lion, however the internals were worked on extensively to add support for iCloud and to resolve various usage and performance issues. The notes here are tips for developer usage.

A Note on Deprecated APIs:

Subtle aspects of deprecated methods in NSSavePanel and NSOpenPanel will not work when your app is sandboxed. Replacement methods have been available for a while, Changing your code to use the supported APIs will not prevent you from disabling the app sandboxing in the future. Now would be a good time to heed the warnings the compiler has been giving you.

Class Hierarchy:

As described in : The App Sandbox Design Guide

The declared (compile-time) class hierarchy for NSOpenPanel and NSSavePanel appears the same for sandboxed and non-sandboxed applications, but the actual (run-time) class hierarchy changes. Early versions of the App Sandbox Design Guide documentation were incorrect. Here is a (correct) recap:

The declared hierarchy looks like this:
NSOpenPanel : NSSavePanel : NSPanel : NSWindow : NSResponder : NSObject
The actual (run-time) hierarchy looks like this:
NSOpenPanel : NSSavePanel : NSObject
if you or anyone to whom you pass an instance of an NSOpenPanel or NSSavePanel assumes that the methods of NSPanel, NSWindow, or NSResponder are available through that instance — your app may encounter a method-not-found exception.

Availability of NSWindow APIs on an instance of NSOpenPanel and NSSavePanel:

In Mountain Lion, in a sandboxed app, you can treat an instance of NSSavePanel or NSOpenPanel as if it were subclassed from NSPanel during three well-defined spans of time: Delegate method calls, panel completion blocks, and accessory view action method calls.

Restricted File Access affects Delegate Method support:

As described in the "Powerbox and File System Access Outside of Your Container" section of the The App Sandbox Design Guide, a sandboxed app has restricted access to the file system unless and until the user specifies otherwise on a file-by-file basis, or your application has extra entitlements to files. The NSOpenPanel and NSSavePanel delegate methods behave the same under App Sandboxing, however what you can do with the URLs supplied by those methods has changed. The URLs passed to these delegate methods cannot be used to obtain information about the objects to which the URLs refer. This means not only that file contents are inaccessible but also object meta-data is inaccessible. In other words, about all you can do with these URLs is analyze them as (standardized, structured) strings.

NSOpenPanel and NSSavePanel are not intended for use within a Sandboxed Application's container directory. The Application container directory is an abstraction which an end user is unlikely to be able to find with Finder. Therefore an Application container directory should not be presented to an end user in the open and save panels either. If your application attempts to set the initial directory of an open or save panel to the Application container directory (or a sub-directory therein), the code in pboxd detects this and redirects the panel to the user's home directory.

Titlebar Renaming

There is no public API for Titlebar Renaming outside of NSDocument. You may note that even if your application is not app sandboxed, an instance of pboxd (aka "Powerbox") is running while a Titlebar Renaming session is in progress. Titlebar Renaming uses pboxd even in non-sandboxed applications.



Changes to Resume for Applications

In order to improve system startup performance, applications which were hidden at time of logout will by default only be partially launched when resuming after a reboot. Such partially relaunched applications use much less system resources. When the user activates an application launched this way, it will be fully restored and behave normally.

If this behavior is undesirable for your application (for example, a mail application may be checking for mail and displaying a count of unread messages in its dock icon even if the user isn't interacting with it), you can use the Automatic Termination APIs to provide information to the system about what your app is doing, allowing it to make more appropriate choices. If an automatic-termination-aware application disables automatic termination via the -[NSProcessInfo disableAutomaticTermination:] API, the OS will assume that it's in the middle of something that should be resumed, and will fully relaunch it on restart. Once automatic termination is reenabled via -[NSProcessInfo enableAutomaticTermination:], the OS will resume deciding between full, partial, or no relaunch to minimize startup time without violating the user's expectations.

Adopt Automatic Termination

Automatic Termination is a facility introduced in OS X Lion. It allows underlying processes to be terminated by the system automatically, independent of the running state of the application itself. We intend to rely on Automatic Termination even more in the future, and encourage you to adopt it in your applications. You can do this by opt'ing into Automatic Termination via the Info.plist entry NSSupportsAutomaticTermination (or calling -[NSProcessInfo setAutomaticTerminationSupportEnabled:YES] early on), and then calling -[NSProcessInfo disableAutomaticTermination:] and -[NSProcessInfo enableAutomaticTermination:] as needed.



NSTextAlternatives

NSTextAlternatives is a new immutable value class that stores a list of alternatives for a piece of text and communicates selection of an alternative via a notification. NSTextAlternatives instances are attached to attributed strings as the value of a new attribute, NSTextAlternativesAttributeName.

In 10.8 the use case for NSTextAlternatives is dictation, but this class is not strictly tied to dictation and may be used for other purposes in future releases.

The class has two attributes:  primaryString (representing the text that was actually chosen and used in the input string), and alternativeStrings (representing the alternative possible interpretations that the user might select instead).  These are separate because the text system needs to deal with them separately, using the primaryString to make sure that the text is still in the same state as when it was entered, and presenting the alternativeStrings via UI similar to that currently used for correction alternatives.

When the user picks one of the alternative strings, the text view calls -noteSelectedAlternativeString: on the NSTextAlternatives object.  Subclasses of NSTextAlternatives may do what they like in this method, but the base class implementation sends a notification NSTextAlternativesSelectedAlternativeStringNotification, with the selected alternative string in the user info under the key @"NSAlternativeString". This way arbitrary objects can listen for user selections of alternative strings.


Additional API for Spellchecking

There is an additional method on NSSpellChecker:
- (NSString *)languageForWordRange:(NSRange)range
inString:(NSString *)string
orthography:(NSOrthography *)orthography;
Clients who have an NSOrthography from NSTextCheckingTypeOrthography checking and wish to determine a specific language from it for a particular word, for example to pass in to -guessesForWordRange:inString:language:inSpellDocumentWithTag:, -correctionForWordRange:inString:language:inSpellDocumentWithTag:, or -completionsForPartialWordRange:inString:language:inSpellDocumentWithTag:, should use this method to obtain it. This method is publicly documented in 10.8 but is available back to 10.7.



NSImage

In 10.8 we've added API to NSImage and NSCustomImageRep allowing clients to delegate drawing to a block:
+[NSImage imageWithSize:flipped:drawingHandler:]
-[NSCustomImageRep initWithSize:flipped:drawingHandler:]
-[NSCustomImageRep drawingHandler]
These APIs make it easy to create an image (or custom image rep) that delegates its drawing to a block. This block is invoked at draw time, allowing drawing to be tweaked as appropriate for the destination context pixel density, color space, and other properties. This API can replace many (but not all) existing uses of lockFocus/unlockFocus. The existing lockFocus implementation performs all drawing against a single bitmap representation. This causes problems when images are moved between displays of different pixel densities (and to a lesser extent, different colorspaces).

Like other non-bitmap image rep types, drawing is cached as appropriate for the destination context. Practically speaking, the drawingHandler block will be invoked the first time the image is drawn to a particular type of destination (1x or 2x screen, for example). Subsequent drawing operations to the same type of destination will reuse the previously generated bitmap.

When drawing, NSImage has always tried to use a representation with at least as many pixels as the destination rectangle. Many apps try to implement banners and 3 part / 9 part images by stretching an NSImage over a much larger area (usually only on a single axis). With the addition of 2x assets these apps are finding this policy displays the 2x image rep when they would prefer the 1x rep. This behavior can be changed by using the new matchesOnlyOnBestFittingAxis property on NSImage. It is still preferable to use NSDrawThreePartImage and NSDrawNinePartImage, when possible.

Since SnowLeopard it has been possible to use NSImage as the contents of a CALayer. With the recent proliferation of 2x assets, this technique is increasingly being used to simplify HIDPI adoption.  This technique does however face certain limitations:

• The contentsGravity of the layer must be kCAGravityResize, kCAGravityResizeAspect, or kCAGravityResizeAspectFill. For all other contentsGravities behavior is undefined.
• When rasterizing a resolution independent representation, or selecting from multiple representations, only the backingScaleFactor of the view hosting the layer is used. This means that any scales introduced by modifying the bounds or transform of the layer or its ancestors are ignored.

In 10.8, NSImage now offers two new methods to more explicitly deal with a layer's contentsScale. These methods are -recommendedLayerContentsScale: and layerContentsForContentsScale:. These methods can be used to account for scales present in the layer tree (for example due to the layer bounds, or a layer transform). They also work for all contentsGravities.
static void updateLayerWithImageInWindow(NSImage *image, CALayer *layer, NSWindow *window)
{
    CGFloat baseScaleFactor = [window backingScaleFactor]; // This is the scale factor of the screen we are displayed on.
    NSSize imageSize = [image size];
    CGRect layerSize = [layer bounds].size;
    CGFloat additionalLayerScaleFactor = fmax(layerSize.width / imageSize.width, layerSize.height / imageSize.height);
    CGFloat desiredScaleFactor = baseScaleFactor * additionalLayerScaleFactor; // this scale factor is appropriate
     // for the actual pixel bounds of the layer.
    CGFloat actualScaleFactor = [image recommendedLayerContentsScale: desiredScaleFactor]; // Don't use a higher scale
     // factor if the image can't provide it. If the image is resolution independent
     // the return value will be the same as the input.
    id layerContents = [image layerContentsForContentsScale:actualScaleFactor]; // Now we have an appropriately
     // sized object to use as the contents of a layer.
    [layer setContents:layerContents];
    [layer setContentsScale:actualScaleFactor];
}

NSWindow

As of 10.7.3, AppKit sends NSWindowDidChangeBackingPropertiesNotification when a window's backingScaleFactor and/or colorSpace changes. When running on a system version where this new notification is available, applications should use it instead of NSWindowDidChangeScreenProfileNotification to watch for changes to either of these backing store properties. There is also a corresponding delegate method.
NSString *NSWindowDidChangeBackingPropertiesNotification;
@protocol NSWindowDelegate <NSObject>
@optional
...
- (void)windowDidChangeBackingProperties:(NSNotification *)notification;
...
@end
The userInfo dictionary contains two keys: NSBackingPropertyOldScaleFactorKey has an NSNumber value that specifies the window's previous backingScaleFactor, and NSBackingPropertyOldColorSpaceKey has an NSColorSpace value that specifies the window's previous colorSpace . You can compare these with the backingScaleFactor and colorSpace at the time of the notification, to determine which of these two properties changed. Note it is possible for both to have changed.
NSString *NSBackingPropertyOldScaleFactorKey;
NSString *NSBackingPropertyOldColorSpaceKey;

NSView

NSView has a new override point: -viewDidChangeBackingProperties. This method provides a simple override point from which a client may apply changes to their layer hierarchy. It will be invoked when the view is added to a window, or when that window changes colorspace or backing scale factor. This method may be overridden to apply the current contentsScale to their layer tree.

Additionally, we have introduced an optional method for CALayer delegates:
- (BOOL)layer:(CALayer *)layer shouldInheritContentsScale:(CGFloat)newScale fromWindow:(NSWindow *)window;
When implemented, NSView will invoke this method on a layer's delegate when the view is added to the window, or the window's resolution changes. NSView does this by enumerating the layer tree attached to it and inspecting each layer delegate in turn. Note that when a layer is added to an already visible layer tree this method will *not* be invoked. If you return YES from this method, NSView will set the layer's contentScale to match the backingScaleFactor of the window it is hosted in; and mark the layer dirty using -setNeedsDisplay.


Managing NSImages with multiple representations

Taking advantage of NSImage's multiple representation capability is important for high resolution support in your apps. NSImage has facility to choose and load the appropriate representation at runtime, depending on the context in which it is being drawn. It will also reload additional representations as needed when asked to draw into different contexts.

Although NSImages with multiple representations can be created at runtime, by calling addRepresentation:, it's often much easier to load such images from files. A call such as [NSImage imageNamed:@"foo"] will create an NSImage backed with all image files named "foo" in your app bundle, for instance foo.png, foo.tiff, foo.pdf, etc. In addition, the tiff file format can contain multiple representations within a single file, eliminating the need to have multiple files. This facility has been in place since OS X 10.0.

When multiple representations are providing for a single image, it's very important that the representations all have the same intrinsic size (as returned by -size). For bitmap image files with different pixel counts this is achieved by setting the density of the image properly. Since the default density of images is 72dpi, setting the density of 2x files to 144dpi achieves this constraint. When creating artwork this is often done by specifying a resolution value in an image sizing panel; programmatically this is done by setting the size of the NSBitmapImageRep explicitly to something other than {pixelsWide, pixelsHigh}.

Starting in 10.7, NSImage added support for the iOS naming convention for high resolution images, which means [NSImage imageNamed:@"foo"] will also pick up foo@2x.png. In such cases the pixel dimensions of the 2x image need to be 2x, and NSImage will assume that the density is twice that of the 1x file.

For artwork coming from bundles other than the app bundle, the 10.7 method -[NSBundle imageForResource:] can be used to do the same combination of individual files.

Despite this multi-file support in NSImage, we don't really expect you to use it much. If you have resources foo.png and foo@2x.png in your project resources, Xcode by default is going to roll them together into a multi-representation foo.tiff that contains both during build. We recommend this approach as a way to reduce the number of files in your shipping app bundles.

Command line tool tiffutil can be used to manually combine individual bitmap image files into single tiff files.

Managing application and document icons

Xcode 4.4 provides support for combining application and document icons, which use the .icns image file format. In your project resources you provide "iconset" folders that contain the individual files which will be combined at build time into .icns files. The format for the iconset folder is described in the document "High Resolution Guidelines for OS X."

Command line tool iconutil can be used to manually combine individual bitmap files into single icns files.

Note that support for icns files with high resolution representations extends back to OS X 10.6, but not 10.5.

NSOpenGL

The NSOpenGLContext methods -setFullScreen and -setOffScreen:width:height:rowbytes: no longer do anything. This is because the functions on which they are are based (CGLSetFullscreen and CGLSetOffScreen) no longer work. Check the documentation for CGLSetFullscreen and CGLSetOffScreen for replacement functionality.



NSColor

There's a new NSColor class method to return the lighter linen color that should be used for backgrounds of pages and revealed view areas:
+ (NSColor *)underPageBackgroundColor;
There are two new NSColor methods to convert back and forth from CGColorRefs:
+ (NSColor *)colorWithCGColor:(CGColorRef)cgColor;
- (CGColorRef)CGColor;
These methods do not guarantee round-trip fidelity. -colorWithCGColor: may return nil in some cases (for instance, it's not implemented for indexed color spaces). -CGColor will never return nil, but the result may be an approximation.

Conversion of colors with -[NSColor colorUsingColorSpace:] using arbitrary spaces has been speeded up greatly to match the speed of conversion using the built-in standard color spaces.



NSProgressIndicator

The bar-style progress indicator now supports progress animation in right-to-left configuration when -[NSApplication userInterfaceLayoutDirection] returns NSUserInterfaceLayoutDirectionRightToLeft.


NSRulerView

The icon for right and left tab markers are correctly rendered in the vertical text orientation.


New gestures for NSTextView

NSTextView supports the Quick Look gesture by implementing new NSResponder APIs, -quickLookPreviewItems: and -quickLookWithEvent:. Also, the smart magnify gesture is supported through -rectForSmartMagnificationAtPoint:inRect:.


NSFont

The default fixed pitch font in Mountain Lion is Menlo 11pt. +[NSFont userFixedPitchFontOfSize:] with 0.0 point size now returns Menlo 11 instead of Monaco 10.

Starting from this release, the default use of screen fonts is discontinued. The text rendering and measurement APIs for user interface elements such as NSStringDrawing and NSCell methods no longer substitute font attributes with their screen font counterparts automatically. The default setting for -[NSLayoutManager usesScreenFonts] is now NO for applications linked on this and later releases. You can keep your applications running with Lion-behavior by setting a new NSUserDefaults key, NSFontDefaultScreenFontSubstitutionEnabled. NSFontDefaultScreenFontSubstitutionEnabled controls the overall default screen font substitution behavior. When set to YES, the screen font substitution is performed by all text APIs just as on previous releases. The default value is NO.

Applications can store the screen font setting into documents via NSUsesScreenFontsDocumentAttribute.




Notes specific to Mac OS X 10.7

Some of the major topics covered in this section include:



Automatic Reference Counting

Automatic Reference Counting (ARC) is a new feature which enables the compiler to generate calls for retain, release, and autorelease. It is available with Xcode 4.2, for Mac OS X and iOS, back to Mac OS X 10.6 and iOS 4. However, on these earlier systems the zeroing weak reference feature of ARC is not available.

On 10.7, some Cocoa classes including NSWindow, NSTextView, NSFont, and NSImage do not support zeroing weak references. Many other classes do.

Unlike garbage collection, ARC does not provide any cycle-detection or breaking features. So traditionally weak references such as delegates, outlets, or targets should remain weak by default under ARC. In most cases this can mean zeroing-weak, although in cases where the object in question is one of those that does not support zeroing weak reference (or you want to deploy on 10.6), you may have to use non-zeroing weak, which is indicated with the variable qualifier __unsafe_unretained or property attribute assign.

Note that Xcode 4.2 defaults to ARC when creating new projects, and in the WWDC seed release generates outlet declarations that are strong (in new projects as well as when adding new outlet declarations from Interface Builder). In most cases these should be changed to weak (zeroing or not) to avoid cycles that may cause leaks.


iCloud

10.7 includes APIs to enable applications to store configuration information and documents in the iCloud. The main APIs here are in a number of Foundation classes; please refer to the Foundation release notes.


Lion's Two Scroller Styles

Lion introduces new, iOS-inspired "Overlay scrollers", as well as restyled "Legacy" scrollers that provide for application compatibility, accessibility, and accommodation of user preferences. Applications should be prepared to work with either style of scroller, and for the system's preferred scroller style to change over time as the user connects/disconnects pointing devices or makes changes to Appearance, Trackpad, or Mouse scrolling preferences.

"Overlay" scrollers are composited atop the margins of an NSScrollView's contentView, instead of subtracting reserved space from the NSScrollView's potential content area. Scroll thumbs appear automatically during gesture-scrolling (as well as programmatically induced scrolling), and disappear after scrolling stops, giving users an uncluttered, content-focused UI. This automatic show/hide behavior and coordination of a horizontal and vertical scroller pair requires a managing NSScrollView, which provides the necessary logic and relationship to the scrollable content area. An NSScroller instance that's used on its own, without being managed by a parent NSScrollView, can be configured to use the Overlay scroller appearance, but will not have the associated animated show/hide behavior.

To avoid interfering with user-content interaction, simply mousing into the content area edges does not cause the Overlay scrollers to change from hidden to shown, since it's possible the user may intend mouse actions in those margins for the underlying content. Gesture-scrolling, or any keyboard equivalent or application-defined action that results in scrolling, is necessary to cause the scrollers to be shown.

Once the Overlay scrollers are shown, any mouse motion within the scrollable content area is sufficient to delay their hiding, which allows time to mouse into either scroller if desired. When the mouse enters an Overlay scroller, the scroller shows its track to aid the user in hitting the desired scroller part, and both scrollers remain pinned to visible until the mouse exits the scroller.

Overlay scrollers offer the familiar mouse-driven capabilities: By mousing into an Overlay scroller, users can drag the scroller knob (including [Option]+drag to achieve fine scrolling) and can click in the scroller track to page or jump (according to the user's "Click in the scroll bar to:" Appearance preference setting).

Application code can programmatically request showing of the Overlay scrollers using the NSScrollView's new -flashScrollers method. This may be desirable when changing a document view's size or swapping new content into the view, or to give the user a sense of the current position within the scrollable range at each step of an incremental search or similar operation. (Without the explicit -flashScrollers message at each find step, the scrollers would be pulsed to visible only when advancing to the next find result happens to cause programmatic scrolling.) -flashScrollers may be sent any number of times; AppKit coalesces the requests into smooth scroller show/hide behavior. An NSScrollView's vertical and horizontal Overlay scrollers always show and hide together. -flashScrollers is OK to send to an NSScrollView that's using the Legacy scroller style, and simply has no effect in that case.

Overlay scrollers are designed for use with gesture-scroll-capable devices. To provide compatibility for various circumstances, including users with Accessibility needs and systems with non-gesture-scroll pointing devices, AppKit also provides a "Legacy" scroller style. Legacy scrollers have been restyled to provide an appearance similar to Overlay scrollers, and no longer have scroll arrow buttons, but are otherwise functionally identical to 10.6 Aqua scrollers: They have the same metrics, have layout space reserved for them instead of being overlaid atop the contentView, and are always visible (except when the "autohidesScrollers" NSScrollView feature is used). NSScroller has a new "scrollerStyle" property that can be consulted to determine the style in use by a particular NSScroller instance. A matching setter method is tentatively provided, but should not in general be used except by NSScrollView's implementation.

The "Appearance" preference panel contains a new "Show scroll bars:" preference that enables users to choose between Overlay and Legacy scrollers. By default, the setting is "Automatically, based on input device", which leaves the decision up to AppKit based on the connected pointing device hardware, but users can also choose "When scrolling" to prefer Overlay scrollers, or "Always" to request Legacy scrollers.

When the setting is "Automatically…" and more than one pointing device is connected, the decision is based on the most capable pointing device that is found, disregarding a built-in trackpad if other pointing devices are present. The idea is that a user who connects a pointing device probably means to use it, but we also don't want to force fallback to the least common denominator when a touch-scroll capable external device is also present. A touch-scroll device that has its touch-scroll capability disabled in the user's Mouse/Trackpad preferences is treated the same as a non-capable device, but, again, the internal trackpad's configuration is disregarded when one or more external pointing devices is present. So, for example, if a user has a MacBook Pro with a Magic Mouse connected, the trackpad's touch-scroll capability can be disabled without causing fallback to Legacy scrollers, as long as the Magic Mouse has its touch-scroll capability enabled.

AppKit updates scrollers at runtime to reflect changes to the user's "Show scroll bars:" Appearance preference, and as pointing devices (including wireless devices) are connected and disconnected.

There are two cases where a particular set of scrollers are forced to the Legacy style, even if the user's preference is set to "Show scroll bars: When scrolling".

An NSScrollView's scrollers may be forced to the Legacy scroller style if AppKit detects the presence of an "accessory view" in the track areas of the NSScrollView. The zoom popup that appears in TextEdit's wrap-to-page mode is an example of such an accessory view. This technique of nudging scrollers aside to make room for additional small informational views or controls was useful when scrollers had space reserved for them separate from the content area, but isn't compatible with scrollers that sit atop the content area and disappear when not in use. Applications that want to make use of Overlay scrollers should seek alternatives to accessory views for presenting the desired functionality. Once the accessory views are removed or moved out of the scroller margins, the ScrollView will again be eligible to use Overlay scrollers.

Instances of an NSScroller subclass are, for compatibility, defaulted to the Legacy scroller style and behavior. NSScroller subclasses can declare themselves to be Overlay-scroller-compatible using the new +isCompatibleWithOverlayScrollers API, allowing customization relative to the Overlay scroller appearance and behavior. See the comments accompanying this method in NSScroller.h for usage and the complete set of compatibility requirements.



NSAnimationContext API Additions

NSAnimationContext now has a “timingFunction” property that’s analogous to the CATransaction API’s “animationTimingFunction”. Animations initiated through the “animator” proxy syntax, that do not have an explicitly specified timingFunction, will inherit the enclosing NSAnimationContext’s timingFunction if it is not nil (which is the NSAnimationContext default).

As with the existing “duration” property, changing an NSAnimationContext’s timingFunction causes the same change in the underlying CATransaction’s animationTimingFunction. Also as with the “duration” property, you may change the timingFunction any number of times within a given NSAnimationContext -beginGrouping/-endGrouping block. Changes to the timingFunction will apply to any animations that are subsequently initiated in that NSAnimationContext grouping (until the timingFunction is possibly changed again).

NSAnimationContext has also been given a new “completionHandler” block. Once set to a non-nil value, a context’s completionHandler is guaranteed to be called (on the main thread) as soon as all animations subsequently added to the current NSAnimationContext grouping have completed (or been cancelled). This API drives the underlying CATransaction "completionBlock" property (though AppKit may assign a different, intermediary completionBlock to the current CATransaction). NSAnimationContext's completionHandler firing waits for all animations to which the handler applies, independent of whether they are evaluated by AppKit or delegated to Core Animation for evaluation in the render tree. If no animations are added before the current NSAnimationContext grouping is ended (or the completionHandler is set to a different value), the handler will be invoked immediately.

Lastly, NSAnimationContext has an accompanying new +runAnimationGroup:completionHandler: class method. Its use provides for more natural syntax, letting you specify a completion block body after the set of animation actions whose completion will trigger the completion block.

The following:
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context){
    // Start some animations.
[[myView animator] setFrameSize:newViewSize];
[[myWindow animator] setFrame:newWindowFrame display:YES];
} completionHandler:^{
    // This block will be invoked when all of the animations started above have completed or been cancelled.
NSLog(@"All done!");
}];
is semantically equivalent to:
[NSAnimationContext beginGrouping];
    [NSAnimationContext setCompletionHandler:^{
// This block will be invoked when all of the animations started below have completed or been cancelled.
NSLog(@"All done!");
    }];
    // Start some animations.
[[myView animator] setFrameSize:newViewSize];
[[myWindow animator] setFrame:newWindowFrame display:YES];
[NSAnimationContext endGrouping];
The “NSAnimationContext *context” parameter passes the thread’s current NSAnimationContext to the block as a convenience, so that code within the block that wants to change or query properties of the current context does not have to query (possibly repeatedly) for [NSAnimationContext currentContext].


NSWindow “animationBehavior” property

In 10.7, we added automatic animation of NSWindow -orderFront:/-orderOut: operations, which can be controlled using the new “animationBehavior” NSWindow property. By default, an NSWindow’s animationBehavior is set to NSWindowAnimationBehaviorDefault, which causes AppKit to determine the style of animation to use automatically based on its inference of a window’s “type” from various window properties. A window’s animationBehavior can be set to NSWindowAnimationBehaviorNone to disable Appkit's automatic animations for the window. (This may be useful if AppKit’s animation interferes with an animation that your application implements.) Or, it can be set to one of the other non-Default NSWindowAnimationBehavior values to override AppKit's automatic inference of appropriate animation behavior based on the window's apparent type.


Custom View Unarchiving and “wantsLayer”

Prior to 10.7, a Custom View being unarchived from a .nib or .xib file would always receive a -setWantsLayer: message during loading, regardless of whether the unarchived wantsLayer setting was YES or NO. Receiving this message with a parameter of NO could interfere needlessly with a wantsLayer==YES setting the view might attempt to make in its -initWithFrame: method. On 10.7, AppKit will only send -setWantsLayer: to a Custom View during unarchiving if the parameter is YES, eliminating this pitfall.



Easier Focus Ring Management

A "focus ring" is an Aqua-tinted halo that indicates a control is the active first responder that will receive key events. New NSView API in 10.7 makes it much easier to specify a focus ring shape to be shown for a custom view, while providing AppKit with the information it needs to automatically ensure consistent focus ring erasure and redraw. This new automatic focus ring model also yields correct results in layer-backed mode, which previously was constrained by the inability of focus ring drawing to extend out, reduces the need for view content redraw in many cases, and even provides a useful hint to Accessibility regarding where the user's attention is likely to be focused.
- (void)drawFocusRingMask NS_AVAILABLE_MAC(10_7);
- (NSRect)focusRingMaskBounds NS_AVAILABLE_MAC(10_7);
- (void)noteFocusRingMaskChanged NS_AVAILABLE_MAC(10_7);
A custom view that wants a focus ring to be shown when it is the active first responder, and that doesn't inherit that behavior from a superclass, needs only specify a focus ring mask shape. AppKit will automatically determine when the focus ring needs to be shown and erased (as the view becomes, and ceases to be, the active first responder -- that is, the firstResponder in the application's keyWindow), and will invoke the -focusRingMaskBounds and -drawFocusRingMask methods as needed.

NSView's implementation of -drawFocusRingMask draws nothing, and its -focusRingMaskBounds method returns an empty rectangle. To opt into the new 10.7 focus ring drawing model, a view simply overrides the -drawFocusRingMask method to draw the shape whose outline should serve as the template for the focus ring, and -focusRingMaskBounds to return the bounding box of that shape (expressed in the view's interior ("bounds") coordinate space). For example, a simple rectangular focus ring surrounding a view's frame would be requested by simply doing:
- (void)drawFocusRingMask {
NSRectFill([self bounds]);
}
- (NSRect)focusRingMaskBounds {
return [self bounds];
}
AppKit will automatically invoke these methods when appropriate, to render the view's focus ring. (Make sure the view is eligible to become its window's firstResponder, by overriding -acceptsFirstResponder to return YES.) The focus ring is rendered using the style specified by the view's focusRingType (which must not be NSFocusRingTypeNone unless you want to suppress drawing of the focus ring). An implementation of -drawFocusRingMask can assume that it is drawing in the view's interior (bounds) coordinate space, and that the fill and stroke colors have been set to an arbitrary fully opaque color. It needs only draw the desired focus ring shape (or an image or other object whose outline defines the focus ring mask).

This model provides an alternative to the previous focus ring technique, wherein a view was responsible for determining when to draw and erase its own focus ring, was required to perform its focus ring drawing explicitly as part of its -drawRect: implementation, and had to use the special -setKeyboardFocusRingNeedsDisplayInRect: method to ensure correct focus ring erasure and redraw. A view that adopts this new 10.7 focus ring API should no longer call NSSetFocusRingStyle() and perform its own focus ring drawing in -drawRect:, unless running on 10.6 or earlier, since the use of NSSetFocusRingStyle() would cause AppKit to fall back to the old focus ring drawing model for the view. Invoking -setKeyboardFocusRingNeedsDisplayInRect: is OK, but will cause more redraw than necessary on 10.7, where AppKit is able to determine the exact coverage of focus ring rendering based on the focus ring mask, and is thus able to show, hide, and move the focus ring with minimal redraw of affected window areas. In layer-backed mode, AppKit draws a focus ring that's implemented using this new 10.7 API into its own layer, which permits the focus ring to extend outside the associated view's backing layer bounds and allows the focus ring to be efficiently shown, moved, and hidden without necessitating redraw of the associated view content.

The third new method, -noteFocusRingMaskChanged, is provided for you to invoke when some state that AppKit doesn't know about (such as which of a set of non-view components of your content you consider "focused"), that affects the focus ring shape or where you'd like it to be drawn, changes. AppKit automatically invokes -noteFocusRingMaskChanged when your view receives a -setNeedsDisplayInRect: message (as happens when the view is resized or moved), and when the view's focusRingType is changed, which covers most cases. It is only necessary to invoke -noteFocusRingMaskChanged in cases where some internal state change of your own, that AppKit can't know about, affects the desired shape or position of your focus ring mask.

For the benefit of cell-based NSControls, there is a parallel set of overridable NSCell API:
- (void)drawFocusRingMaskWithFrame:(NSRect)cellFrame inView:(NSView *)controlView NS_AVAILABLE_MAC(10_7);
- (NSRect)focusRingMaskBoundsForFrame:(NSRect)cellFrame inView:(NSView *)controlView NS_AVAILABLE_MAC(10_7);
There is no NSCell equivalent to -noteFocusRingMaskChanged. When a cell determines that its focus ring mask needs updating, in a situation where the cell’s content is not otherwise being redrawn, it can invoke [[self controlView] noteFocusRingMaskChanged].

New Tiling Model for Layer-Backed Views

Handling of large views poses a fundamental challenge for a layer-backed rendering model, as it implies the need to allocate commensurately large layer backing stores that consume memory and may exceed the maximum allowable texture size of the host system's graphics hardware. Some form of tiling is necessary, to enable the needed, visible portions of a view to be buffered, while potentially large regions that aren't currently visible (e.g. parts of a document view that are scrolled out of view) are free to be unbuffered until they are made visible.
In 10.5 and 10.6, AppKit's tiling model was based on Core Animation's CATiledLayer, and assumed that the documentView of an NSScrollView, and only the documentView of an NSScrollView, should receive a tiled backing layer. This approach permitted common case of large layer-backed documentViews, but didn't address the potential for other views to exceed the maximum texture size, and came with asynchronous drawing behavior (fade-in of tiles as they were drawn) that in some cases didn't yield the right user experience.
On 10.7, AppKit uses an entirely new, synchronous tiling implementation that eliminates the visual tile-fade-in artifacts associated with the previous model, and that automatically tiles and untiles view backing layers as necessary based on the view's size, rather than being tied to the assumption that only an NSScrollView's documentView is likely to be large. A layer-backed view that is tiled will be called to draw via the usual -drawRect: mechanism to draw portions of its content to be cached into tiles. AppKit automatically manages the creation and population of tile layers, which reside under a "tile container layer" parent that AppKit adds as a sublayer of the view's normal backing layer.
The new tiling model is automatic and does not require the use of any new API, but responds to a set of user defaults that can be used to experimentally tune its parameters on a per-process basis. These user defaults should be considered private and subject to change in future releases, but the ability to adjust them might be of use if the standard values prove unsuitable for a particular application.
NSViewBackingLayerTileSize determines the tile size, and defaults to 512 (pixels on a side). Power-of-two values are recommended. (512 * 512 * 4bytes/pixel) = 1MB per tile. Larger values produce fewer tiles and reduce tile management overhead, but will tend to waste more space for views whose frames don't map to an integral number of tiles.

NSViewMaxNonTiledBackingLayerSize specifies the maximum size (in pixels) that a view's backing layer can be on either side before the view is forced to be tiled. The default is 2000 pixels.

NSViewMaxResidentTiles determines the maximum number of tile backing stores that can be allocated for the process. When AppKit reaches this limit, it begins discarding the contents of non-visible tiles to make room for new visible tiles. The default is 64.

NSAppKitBackingLayerTiling controls the new tiling model, and defaults to YES. It can be set to NO to revert to the 10.6 tiling behavior (use of CATiledLayer backing layers for NSScrollViews' documentViews).

NSDebugBackingLayerTiling can be set to YES to enable informative logging regarding tiling activity. The output could be useful in assessing and tuning performance, or when filing a bug report.


NSOpenGL and Resolution Independence

As part of 10.7's updated Resolution Independence architecture, individual views have a new means to declare their compatibility with high-resolution framebuffers. Since OpenGL is innately a pixel-oriented API and much existing OpenGL code does not function correctly when "surprised" with a high-resolution backing store, OpenGL views are run in scaled mode by default, and need to specifically opt into high-resolution backing.

The accessors for this new property are declared in a category on NSView in NSOpenGLView.h, to emphasize that their relevance is confined to OpenGL rendering, but the property is applicable to any view that renders using an associated NSOpenGLContext.
@interface NSView (NSOpenGLSurfaceResolution)
- (BOOL)wantsBestResolutionOpenGLSurface NS_AVAILABLE_MAC(10_7);
- (void)setWantsBestResolutionOpenGLSurface:(BOOL)flag NS_AVAILABLE_MAC(10_7);
@end
The "wantsBestResolutionOpenGLSurface" property specifies whether a given view instance wants, and is capable of correctly handling, an OpenGL backing surface (framebuffer) with resolution greater than 1 pixel per point. This property is relevant only for views to which an NSOpenGLContext is bound (including, but not limited to, NSOpenGLViews); its value does not affect the behavior of other views, including CALayer-backed views (which may choose to render at a higher surface resolution independent of this property's value. For compatibility, wantsBestResolutionOpenGLSurface defaults to NO, providing a 1 pixel per point framebuffer regardless of the backing scale factor for the display the view occupies. (When the backing scale factor is > 1.0, the rendered surface contents are scaled up to the appropriate apparent size.) Setting this property to YES for a given view gives AppKit permission to allocate a higher-resolution framebuffer when appropriate for the backing scale factor and target display. AppKit may vary the surface resolution when the display mode is changed or the view is moved to a different display, but with this property set to YES it is capable of allocating a surface of greater than 1 pixel per point for the view.

To function correctly with wantsBestResolutionOpenGLSurface set to YES, a view must take care to perform correct conversions between view units and pixel units when needed. For example: The common practice of passing the width and height of [self bounds] to glViewport() will yield incorrect results (partial instead of complete coverage of the render surface) at backing scale factors other than 1.0, since the parameters to glViewport() must be expressed in pixels. Instead, use the dimensions of [self convertRectToBacking:[self bounds]], which are in appropriate (pixel) units.

The "wantsBestResolutionOpenGLSurface" property is archived (keyed archiving required).

For testing purposes only, the effect of this property can be overridden globally for all views in a process, using the "NSSurfaceResolution" user default. If NSSurfaceResolution is set to "Device", all views that have surfaces (including not only OpenGL surfaces, but layer tree render surfaces as well) will be opted into using the best resolution surface for the primary display the view is presented on. This can be used to quickly assess whether an apps view's are ready for non-1x surfaces. If NSSurfaceResolution is set to "1x", all views that have surfaces will be opted into using 1x (1 pixel per point) surfaces, independent of the display or backing scale factor. If NSSurfaceResolution is set to any other value, or no value is present for it, then wantsBestResolutionOpenGLSurface will be consulted as described above for views that perform NSOpenGL rendering, and AppKit will separately determine the appropriate resolution for other surfaces, as also described above.



NSView now passes unhandled -rightMouseDown: events up the responder chain

Prior to 10.7, NSView did not pass unhandled -rightMouseDown: events up the responder chain. On 10.7, NSView passes -rightMouseDown: up the responder chain, if AppKit doesn’t find an associated context menu to display for the view. To avoid binary compatibility issues, this new behavior is enabled only for applications linked on 10.7 or later.




Deprecation of Pixel Buffers (PBuffers)

Pixel Buffers (PBuffers) have been deprecated in 10.7. Modern clients should use Frame Buffer Objects (FBOs) instead of NSOpenGLPixelBuffer and associated methods. See GL_EXT_framebuffer_object.



Deprecation of NSOpenGLContext -setOffScreen:width:height:rowbytes:

NSOpenGLContext’s -setOffScreen:width:height:rowbytes: API should be considered deprecated as of 10.7. As noted in NSOpenGL.h, this API forces use of the software rasterizer, which is much slower than GPU rendering. It is generally much better nowadays to use a normal pixel format with either an off-screen window or an FBO (Frame Buffer Object), and then call glReadPixels() to read the rendered result back to CPU memory (if that's where it is needed).



Changes for Resolution Independence

Significant changes have been made to the underlying graphics model for resolution independence, and the behavior of Cocoa applications running under high resolution operation has been updated. Scaling of user interface content is now limited to an integral 2x scale factor, and is keyed off of per display settings rather than a global scale factor. Pixel-accurate high resolution bitmap artwork now only needs to be provided at a 2x size multiple, similar to the operation of iOS on a Retina display.

The underlying device pixel geometry of both window backing stores and screen frame buffers has been virtualized and abstracted behind new point-based coordinate spaces for NSWindow and NSScreen. The relationship between pixels and points is now driven by attributes of the display mode any given display is operating in. When a display is configured to run in one of the new "HiDPI" modes, the corresponding NSScreen object and any windows created on that display are automatically scaled with a 2:1 pixel per point backing ratio.

The implication of this change is that under high resolution operation, rectangles, sizes and positions are all unchanged from low resolution operation, and are now universally assumed to be in points. Previously, event coordinates and both the window base coordinate system and the screen global coordinate system were presumed to be in device pixels, and were in an "unscaled" space compared to view coordinates. This is no longer the case: window frame coordinates, event coordinates and view coordinates converted to window space are all expressed in points and do not change between low and high resolution operation. The relevant scaling and mapping to the display is performed automatically by the Quartz Window Manager and by the NSGraphicsContext attached to any given window.

Coordinate Space Conversion

The consequence of window and screen device virtualization is significantly enhanced application compatibility under high resolution operation, and under most circumstances, apps will not need to be aware of the underlying pixel geometry of their windows. However, circumstances can arise where applications may wish to perform pixel-accurate drawing operations to optimize or align their content under high resolution operation. To address these needs, a complete set of new coordinate space conversion methods have been introduced to go back and forth between virtual point geometry and a pixel aligned coordinate system matching the characteristics of the backing store for that object.

All of the methods below are defined on NSView, NSWindow and NSScreen.
/* New methods for converting to and from backing store pixels */
- (NSPoint)convertPointToBacking:(NSPoint)aPoint
- (NSPoint)convertPointFromBacking:(NSPoint)aPoint
- (NSSize)convertSizeToBacking:(NSSize)aSize
- (NSSize)convertSizeFromBacking:(NSSize)aSize
- (NSRect)convertRectToBacking:(NSRect)aRect
- (NSRect)convertRectFromBacking:(NSRect)aRect
In order to provide a conceptually consistent mapping between window and screen coordinates in the face of screen device virtualization, two new methods have been introduced on NSWindow. Under high resolution operation, these methods now simply offset the given rectangle based on the window's position in screen space. No scaling transform is necessary since both coordinate systems are virtual and aligned in point space.
- (NSRect)convertRectToScreen:(NSRect)aRect
- (NSRect)convertRectFromScreen:(NSRect)aRect

Deprecated Coordinate Conversion Methods

As a result of the virtualization of window and screen coordinates, the concept of the 'base' coordinate system has been deprecated, along with methods referring to that coordinate space. The following methods have now been superseded by the convertToBacking methods detailed above.
/* NSView deprecated methods */
- (NSPoint)convertPointToBase:(NSPoint)aPoint
- (NSPoint)convertPointFromBase:(NSPoint)aPoint
- (NSSize)convertSizeToBase:(NSSize)aSize
- (NSSize)convertSizeFromBase:(NSSize)aSize
- (NSRect)convertRectToBase:(NSRect)aRect
- (NSRect)convertRectFromBase:(NSRect)aRect
/* NSWindow deprecated methods */
- (NSPoint)convertBaseToScreen:(NSPoint)aPoint
- (NSPoint)convertScreenToBase:(NSPoint)aPoint

Compatibility Notes for High Resolution Operation

It is important to note that in order to maximize backwards compatibility, the deprecated NSView and NSWindow methods will retain their historic compatible and documented behaviors.

When running at @2x, the behavior of these  methods will still remain consistent with their previously documented semantics, but there will be an unavoidable break in compatibility for code which feeds pixel-based positions (e.g. resulting from -[NSView convertPointToBase:]) into -[NSWindow convertScreenFromBase:].

Application software calling -convertBaseTo/FromScreen: incorrectly will need to adopt the new routines and/or ensure that they refrain from using NSView's convertTo/FromBase routines when providing input positions, and instead use -[NSView convertPoint:To/FromView:nil] instead.  (Note: This is the way everyone did things anyway prior to 10.5 when -[NSView convertTo/FromBase:] was introduced)

Backing Aligned Drawing under High Resolution Operation

One of the most common reasons for making drawing code aware of its underlying backing pixel geometry is to perform rounding to ensure pixel aligned drawing or layout. Although NSView's -centerScanRect: has been updated to work correctly under high resolution operation, some scenarios call for tighter control over the rounding behavior of the alignment operation on each edge of a rectangle. We have introduced a new convenience method to satisfy this need, built on top of the services provided by Foundation's NSIntegralRectWithOptions() API.

This method is available on NSView, NSWindow and NSScreen.
- (NSRect)backingAlignedRect:(NSRect)aRect options:(NSAlignmentOptions)options
This method accepts rectangles in local (virtual) coordinates and ensure that the result is aligned on backing store pixel boundaries, subject to specific rounding hints given in the options argument. Foundation already provides NSIntegralRect(), which takes a rectangle and pushes each edge outward to the nearest integral boundary.  The new method is a slightly more flexible version that gives you control over how the rect is massaged into being integral, after the input rectangle is converted to the appropriate backing space.

Determining Scale Factor

The move to virtualization of screen space and event coordinates fortunately means that developers remain isolated from the hardware details of the displays they are presenting their content on.

There are some scenarios, however, where an app that is resolution-aware may want to reason on its own about the display environment it is running in, and make decisions or computations that are not effectively covered by existing API. These circumstances require an efficient way to determine the effective scale factor of the current display environment.

A new public method will be introduced that returns the effective scale relationship between virtual and physical coordinates for a given screen in it's current mode.  This factor can be thought of as the extra multiple of device pixels which the system has determined need to be used when representing user content on the given display.
/* NSScreen and NSWindow methods */
- (CGFloat)backingScaleFactor
This method is expected to return 2.0 for high resolution scaled display modes, and 1.0 for all other cases.

An identical API is needed on NSWindow to report the scale factor relationship of its backing store pixels to virtual window coordinates, since that relationship is independent of its containing screen. This method is critically useful for contexts where a window exists, but the graphics context may not be setup yet or may be ambiguous.  As an example, consider an off screen window.  The AppKit will ensure that this method will return a 'reasonable' answer depending on the available display environment.

It is important to note that this number returned by this method does not represent anything concrete, such as pixel density or physical size, since it can vary based on the configured display mode. For example, the display may be in a mirrored configuration that is still high resolution scaled, resulting in pixel geometry that may not match the native resolution of the display device.

For almost all common cases, developers should avoid keying off of or using the backingScaleFactor as an input to layout or drawing calculations. Developers should avail themselves of the backing coordinate space conversion methods instead, as the resulting code will more likely work consistently and correctly under both low and high resolution operation.


Window edge resizing

In 10.7, windows may be resized from all edges and corners, and the resize indicator has been removed. This affects all Cocoa apps, and no new API is associated with this behavior. The existing live resize support functions continue to function for all resize directions, and the best practices for maximum live resize performance are unchanged. The setShowsResizeIndicator: method is ignored and the NSWindow method showsResizeIndicator always returns NO.

The cursor also changes to indicate when a click will result in a resize operation, and in which direction. The available resize directions are determined from the minSize and maxSize of a window, and of course whether NSResizableWindowMask is set. Previously it was possible to limit resizing with the NSWindow delegate method windowWillResize:toSize:, but this approach will produce misleading cursors, so prefer to set a minSize and maxSize in addition to (or instead of) this delegate method.

NSWorkspace's NotificationCenter and Blocks

In SnowLeopard, the blocks-based API was not reliable for adding observers to the special notifications vended by NSWorkspace's notification center (such as NSWorkspaceDidTerminateApplicationNotification). Specifically, at least one observer would have to use the target - selector based API for the notification to be successfully received by the blocks-based API.

In 10.7, this has been resolved, so that NSWorkspace's notification center works with the blocks-based API in all cases.

NSWorkspace openURLs: return value

In 10.7, the NSWorkspace method - (BOOL)openURLs: withAppBundleIdentifier: options: additionalEventParamDescriptor: launchIdentifiers: will now return NO and not open anything, if the bundle identifier does not refer to an existing app. In SnowLeopard and earlier, it would return YES, ignore the bundle ID, and open the URLs with the default apps. If the bundle identifier is nil or empty, it will use the default application for the URLs (which is the same behavior on SnowLeopard and earlier).

To determine if a bundle identifier is valid, you can use the absolutePathForAppBundleWithIdentifier: method.

NSWorkspace setDesktopImageURL: now works with folders

In 10.7, you may pass a URL to a folder to the NSWorkspace desktop image API, and the desktop will cycle through the images in the folder (non-recursively). Similarly, the desktopImageURLForScreen: API may return a URL to a folder.

Self Service

Before 10.7, if an application invoked its own Service and the Service has return types, the app would deadlock until the timeout (or the user hits escape). In 10.7, an application can invoke its own Service without deadlock.


Restorable State

In 10.7, AppKit supports a way for applications to restore their state when relaunched. See the methods in NSWindowRestoration.h for more information.

Ignoring Existing Restorable State

When the user default ApplePersistenceIgnoreState is defined, existing restorable state and Untitled documents are ignored. New restorable state and Untitled document autosaves are redirected to a temporary directory, whose path will be logged to the console. This user default is intended for automated tests that want to start with a clean environment, and for debugging.

Toolbar Versioning

In 10.7, when apps add items to their default toolbar (perhaps in new versions), users with customized toolbars will have the new items automatically added.Prior to 10.7, if an application added a new item to a toolbar's default item list, that new item would not appear for users with customized toolbars. This is because the NSToolbar simply stored the list of items in the customized toolbar, so there was no way to distinguish between an item that was removed by the user, and an item that was not available when the app was last run.

In 10.7, NSToolbar records both the customized list of items and the default items. When run on a system with one or more new items in the default array, it will insert the new item into the customized toolbar. NSToolbar makes a best-effort attempt to add it at a location that reflects its position in the default array, but it will always be added somewhere.

Furthermore, if the customized toolbar is identical to the default toolbar, the customizations are no longer recorded at all, so that all changes to the default array are reflected.

These changes are automatically applied when the app is run on 10.7 (so the user must have launched the previous version of the app at least once on 10.7). No app adoption is necessary to take advantage of these enhancements.

NSWorkspace recycleURLs Changes for Volumes Without Trash

In SnowLeopard, if you use use recycleURLs: on a volume that does not support trash, such as an AFP mount, the files would not be moved and the result would be a "file not found" error. In 10.7, this method has changed to prompt the user to either delete the files or to cancel. Canceling results in NSUserCanceledError, while deleting results in the error obtained from attempting to delete the file, or no error if the file is successfully deleted.

Text and Search Fields in Toolbars

In 10.7, search fields and text fields draw slightly differently when they are within toolbars, compared to within the window's content view. The toolbar variant requires one additional point, so text and search fields in toolbars will have their height automatically increased to at least 23 points. Furthermore, if an NSToolbarItem has a search field as its view, that search field automatically has its minimum and maximum size adjusted to the system-specified standard values (currently 140 and 240 points).

Toolbar Contextual Menu Changes

In 10.7, NSToolbar no longer allows users to control the visibility priority of toolbar items, although users can still add and remove items. Furthermore, the Remove Item menu item has itself been removed, except when running with Voice Over.

Toolbar Separator and Customize items removed

In 10.7, the Customize Toolbar item and the Separator item (with the vertical dots) have been removed from toolbars and customization palettes, and their item identifiers are ignored.

Right to Left in -[NSMenu popUpMenuPositioningItem:atLocation:inView:]

In 10.7, the NSMenu method popUpMenuPositioningItem:atLocation:inView: will position the menu to the right of the passed-in point, when running in a right to left context. See the description of the method in the NSMenu.h header for more information.

NSResizableWindowMask and window title bars

Prior to 10.7, passing NSResizableWindowMask to NSWindow init methods would create the window with a titlebar, as if you had passed NSTitledWindowMask. In 10.7, this is no longer true: passing NSResizableWindowMask without NSTitledWindowMask will create a resizable window with no titlebar. For compatibility, this change only affects applications compiled on 10.7 or later, and only affects windows loaded from nibs that were saved on 10.7.

For maximum compatibility, you should of course specify NSTitledWindowMask whenever you want a window to have a titlebar.

Untitled windows at launch

As part of the restorable windows feature, the application delegate may not be asked to create an Untitled window at launch in some circumstances. This was found to cause crashes in certain apps, so these apps will maintain 10.6 behavior of more often opening Untitled windows. When these apps are recompiled on 10.7, they will acquire the 10.7 behavior. For maximum compatibility, do not depend on being asked to create an Untitled window at launch.

Rounded Popup Button Widths

In 10.7, the blue indicator region of rounded popup buttons has been removed, and so the button's content (such as its title) is allowed to consume more space. Be aware when designing on 10.7 that a rounded popup button that does not clip on 10.7 may clip when run on earlier versions.



Modernized Document Model

Mac OS 10.7 introduces a modernized document model in which:
• The user does not have to manually manage multiple copies of their document files to be able to retrieve old versions that they deemed interesting at some point in the past.
• The user is not bothered by alerts asking what to do with unsaved document changes when closing documents or terminating applications. (See other sections of this release note for changes to when applications are terminated.)
• The user does not have to know and take care to save document changes before causing the document’s file to be read by another application. For example, if the user drags a document’s icon from the Finder and drops it in a Mail message editing window to make an attachment then the attachment will always include all of the changes the user had made to the document up to that point. In other words, from the user's point of view a document as presented in an application window is simply the same thing as the document file presented by the Finder, and vice versa.

The next several sections describe changes to NSDocument that you have to know about to make your application conform to the modernized document model.

NSDocument Autosaving in Place

Mac OS 10.4 introduced to NSDocument the “autosaving” of documents to protect against the user losing work due to application crashes, kernel panics, and power failures. You can easily create an NSDocument-based application that periodically saves the current contents of a document to a file next to the actual document file in the file system and having a name like “My Great Document (Autosaved).” Autosaved content files for documents that have never been saved and so don’t yet have document files go in ~/Library/Autosave Information. NSDocument takes care of triggering periodic autosaving, choosing where autosaved document contents file go, invoking your NSDocument subclass’ code for document file writing, cleaning up autosaved document contents files when they are redundant, and reopening autosaved documents when the application is relaunched after an apparent malfunction.

Autosaving still serves the purpose of protecting against malfunction but is now also an important part of NSDocument’s implementation of Mac OS 10.7’s modernized document model. A new kind of autosaving, autosaving in place, has been added. Autosaving in place is different from the old kind of autosaving in that it overwrites the actual document file instead of writing a separate document contents file next to it in the file system. The old kind of autosaving, now called autosaving elsewhere, is still supported for backward binary compatibility and also for when the document has never been saved, so there is no document file, and autosaving requires writing to some other file. You enable autosaving in place, and a wide variety of new behaviors that follow from it, for NSDocument subclasses in your application by overriding a new class method and returning YES from your override:
+ (BOOL)autosavesInPlace;
So that your NSDocument subclass' overrides of -save… and write… methods can distinguish between the two kinds of autosaving the NSAutosaveOperation enumerator that was published in Mac OS 10.4 has been renamed and a new one has been added:
    NSAutosaveOperation = 3,
NSAutosaveElsewhereOperation = 3,
    NSAutosaveInPlaceOperation = 4
In Mac OS 10.4 through Mac OS 10.6 “autosaving” was a misnomer because it was not synonymous with “automatic saving,” which would be the writing of a document’s current documents to the document’s file and the updating of NSDocument attributes that has to be done when that happens. In Mac OS 10.7 NSDocument's new autosaving in place really is automatic saving.

Autosaving in place can sometimes result in the user changing document files that they did not really mean to change. To protect against that, NSDocument does autosaving safety checking when the user changes the document. Examples are checking for documents that are old (does the user really want to edit last year's tax return?) and checking for documents that are in folders where the user typically does not edit documents (does the user really want to edit something they just downloaded?). You can override a new method to customize this checking:
- (BOOL)checkAutosavingSafetyAndReturnError:(NSError **)outError;
See the comments in <AppKit/NSDocument.h> for details.

NSDocument Autosaving Changes

In Mac OS 10.7 the manner in which NSDocument triggers periodic autosaving for crash protection is more complicated than simply setting a timer when the user changes the document. There is no way to customize this behavior other than using the existing -setAutosavingDelay: and -autosavingDelay methods in NSDocumentController but there is a new NSDocument method you can override to implement your own behavior:
- (void)scheduleAutosaving;
This method is invoked by -updateChangeCount: and -updateChangeCountWithToken:forSaveOperation:.

Turning on autosaving in place in your NSDocument-based application changes what NSDocument does when the user closes the document and there are unsaved changes. Instead of presenting an alert asking the user what to do with the changes, NSDocument simply autosaves the document before it is closed. That autosaving is not done by invoking the existing -autosaveDocumentWithDelegate:didAutosaveSelector:contextInfo: method. Instead it is done by invoking a new method:
- (void)autosaveWithImplicitCancellability:(BOOL)autosavingIsImplicitlyCancellable
completionHandler:(void (^)(NSError *errorOrNil))completionHandler;
See the comments in <AppKit/NSDocument.h> for details.

Things to Watch For When Enabling NSDocument Autosaving in Place

Enabling autosaving in place in your application may require other changes to your NSDocument subclass. Here are some things to watch for:

• Turning on asynchronous saving

Because autosaving happens periodically, at unpredictable times while the user is editing the document, user interface delays during saving are less acceptable than they were. When you turn on autosaving in place you should strongly consider also turning on asynchronous saving. See the next section.

• Invoking and overriding deprecated methods

Over the years many NSDocument methods have been deprecated. Notably, in Mac OS 10.4 new methods that take NSURLs and return NSErrors replaced methods that do not. You should update your application to stop invoking and overriding the replaced methods. They are listed at the bottom of <AppKit/NSDocument.h>.

• Overriding -revertToContentsOfURL:ofType:error:

When you enable autosaving in place you also enable version preserving. (Unless you also override +preservesVersions to turn version preserving off.) With autosaving in place enabled it's more important than ever to invoke super when you override -revertToContentsOfURL:ofType:error:, because it's NSDocument's default implementation of that method that updates the document's state to reflect what happens during reverting to an old version. If you don't, NSDocument might present the user with alerts about the document having been changed by another application when that is not the case.

Your override of -revertToContentsOfURL:ofType:error: may now be passed a URL that is not the same as the document's current file URL, and a file type that is not the same as the document's current file type.

• Overriding the various -write… methods

During duplicating and reverting NSDocument may cause the current version of the document, the one the user is looking at at that moment, to be preserved. Doing this sometimes requires that the document's current contents be written to disk. NSDocument does not invoke any of the -save… methods in that case. Instead, it invokes -writeSafelyToURL:ofType:forSaveOperation:error:, passing it a URL to a file that will become the preserved version, the file type that [self autosavingFileType] returns, and NSAutosaveElsewhereOperation. Your NSDocument subclass must write the entire contents of the document to that file. You will probably not notice this if you are not overriding -writeSafelyToURL:ofType:forSaveOperation:error:, you are correctly overriding one of the simple writing methods, which are -writeToURL:ofType:error:, -fileWrapperOfType:error:, and -dataOfType:error:, and if -autosavingFileType always returns an appropriate value.

Simple duplicating may cause the same kind of writing to be done. In that case the file that is written will be used as the already-autosaved contents of the new document.

• Overriding -keepBackupFile

You should not override -keepBackupFile in such a way that it returns YES when +autosavesInPlace returns YES.

• Overriding -autosaveDocumentWithDelegate:didAutosaveSelector:contextInfo:

When autosaving in place is enabled not all autosaving is done by an invocation of -autosaveDocumentWithDelegate:didAutosaveSelector:contextInfo:, so it is not a good method to override to customize all kinds of autosaving. Consider overriding -saveToURL:ofType:forSaveOperation:completionHandler: and checking the passed-in save operation type instead.

• Overriding -validateUserInterfaceItem: and -validateMenuItem:

Enabling autosaving in place adds a popup menu to the title bar of document windows. The popup menu has actions that must be validated by the NSDocument instance. If you override -validateUserInterfaceItem: or -validateMenuItem: you should make sure your override invokes super when the action is not one that your subclass recognizes.

• Updating of the File menu

In applications that have enabled autosaving in place, the Save As… and Save All items in the File menu are hidden, and a Duplicate menu item is added.

• The meaning of NSDocumentController's -setAutosavingDelay: and -autosavingDelay methods

In applications that have enabled autosaving in place, as opposed to the old style of autosaving that was introduced in Mac OS 10.4, passing a value of -[NSDocumentController setAutosavingDelay:] to 0.0 does not turn off autosaving.


NSDocument Asynchronous Saving

Mac OS 10.7 introduces to NSDocument the notion of asynchronous saving, in which the writing to a file being saved is done on a background thread so the application's user interface remains responsive even if that writing is slow. Saving is now done by a new method that does not have to signal success or failure before it returns:
- (void)saveToURL:(NSURL *)url
ofType:(NSString *)typeName
forSaveOperation:(NSSaveOperationType)saveOperation
completionHandler:(void (^)(NSError *errorOrNil))completionHandler;
-saveToURL:ofType:forSaveOperation:error:, the old, synchronous, variant of this method, is deprecated. If your application is overriding that method to customize saving you should override this new method instead. If your application must continue to run on versions of Mac OS X older than 10.7 you can leave your override of the old method there. If you do that then NSDocument will invoke the old method on Mac OS 10.6 and older and the new one on Mac OS 10.7 and newer.

Whether or not saving is asynchronous is controlled by a new method that you can override:
- (BOOL)canAsynchronouslyWriteToURL:(NSURL *)url
ofType:(NSString *)typeName
forSaveOperation:(NSSaveOperationType)saveOperation;
This method is invoked during saving. If your override of it returns YES then NSDocument will create a separate writing thread and invoke -writeSafelyToURL:ofType:forSaveOperation:error: on it, but the main thread will remain blocked until something on the writing thread invokes another new method:
- (void)unblockUserInteraction;
When this method is invoked the main thread will become unblocked, the application will resume dequeueing user interface events, and the user will be able to continue viewing and editing their document, even if the actual writing of the file takes some time. The right moment to invoke this method is when an immutable "snapshot" of the document's contents has been taken so that the writing of the snapshot's contents can continue safely on the writing thread even when the user is editing the document on the main thread. In many applications taking that snapshot will be as simple as creating an NSFileWrapper, so the default implementation of -writeToURL:ofType:error: invokes - unblockUserInteraction after it has invoked -fileWrapperOfType:error: but before writing that NSFileWrapper to a file. If your NSDocument subclass simply overrides -fileWrapperOfType:error: or -dataOfType:error: to implement writing and your override never takes too long to return then you don't have to worry about invoking -unblockUserInteraction.

There is an error in the comment for this method in <AppKit/NSDocument.h>. The default implementation of -fileWrapperOfType:error: does not invoke -unblockUserInteraction. The default implementation of -writeToURL:ofType:error:, on the other hand, does.

In some applications taking a snapshot quickly enough won't be possible all of the time regardless of whether it's an NSFileWrapper or something else. One way to unblock user interaction quickly in that case is to not take a snapshot at all and instead trigger copy-on-write behavior ("write" in this case refers to the mutation of the document's contents in memory, not the writing to a file). In a copy-on-write model objects that are to be mutated to reflect the user's edits are first copied if writing to a file is happening right then so that the writing thread can continue its work without risk of writing a file whose contents are internally inconsistent. While writing continues the values that are displayed in the user interface must be gotten from the copies if there are any, and when the writing is done the copies must be folded back into the document model's regular object graph.

In a substantial application multithreaded copy-on-write is difficult to implement. In an effort to strike a more realistic balance between responsiveness and ease of implementation NSDocument's asynchronous saving machinery also supports a "stop-copying-on-write" model, in which your NSDocument subclass can attempt to take the snapshot mentioned above but often cancel that snapshotting, and actually the entire saving operation, if it takes so long that the user's continued editing of the document requires the mutation of the objects being snapshotted. Implementing this correctly requires implementing a thread-safe way to cancel snapshotting and also a way to sense when the snapshotting must be cancelled. Hopefully this will still be easier for application developers than copy-on-write. To find out when that sort of snapshotting cancellation is appropriate for a particular save operation you can invoke a new method:
- (BOOL)autosavingIsImplicitlyCancellable;
This method returns YES, for example, when periodic autosaving is being done for crash protection and therefore nothing bad would happen if that autosaving were to be cancelled by your stop-copying-on-write mechanism. It returns NO when autosaving should be allowed to continue even it is going to take a noticeable amount of time, when the document is being closed for example.

When saving is asynchronous and the user is allowed to edit a document while it is being saved NSDocument's old technique of updating the changedness of the document after successful saving by invoking -updateChangeCount and passing it NSChangeCleared or NSChangeAutosaved is not sufficient. Information must be recorded about the state of the document at the beginning of the save operation and used at the end. NSDocument now does that, using two new methods:
- (id)changeCountTokenForSaveOperation:(NSSaveOperationType)saveOperation;
- (void)updateChangeCountWithToken:(id)changeCount
forSaveOperation:(NSSaveOperationType)saveOperation;
See the comments in <AppKit/NSDocument.h> for details about all of the methods published in this section.

NSDocument UI and File Access Serialization

With asynchronous saving it is possible for the user to instigate a user interface action that might present modal UI, a sheet for example, when asynchronous saving is about to fail and present an error alert sheet of its own, which would not work. This problem is prevented by the use of a set of new methods:
- (void)performActivityWithSynchronousWaiting:(BOOL)waitSynchronously
usingBlock:(void (^)(void (^activityCompletionHandler)(void)))block
- (void)continueActivityUsingBlock:(void (^)(void))block;
As a general rule you should use these methods, if your NSDocument subclass supports asynchronous saving, around the performance of user interface actions that might present modal UI, like sheets, including error alerts.

For any instance of NSDocument there are values in memory that only make sense in the context of the document file's current state. Problems arise when one thread gets or sets these values while a different thread is changing the file's current state. These problems are prevented by the use of a different set of new methods:
- (void)performSynchronousFileAccessUsingBlock:(void (^)(void))block;
- (void)performAsynchronousFileAccessUsingBlock:(void (^)(void (^completionHandler)(void)))block;
You should use these methods, if your NSDocument subclass supports asynchronous saving, in code that makes decisions based on values that are changed by the act of saving a document, and in code that changes those values.

-performActivityWithSynchronousWaiting:usingBlock: and -performSynchronousFileAccessUsingBlock: can block the main thread. Sometimes that blocking must be interrupted. You can do that, using another new method:
- (void)continueAsynchronousWorkOnMainThreadUsingBlock:(void (^)(void))block;
See the comments in <AppKit/NSDocument.h> for details about all of the methods published in this section.

NSDocument Duplicating

Part of Mac OS 10.7's new document model is a Duplicate item in the File menu that replaces the existing Save As… item, so turning on autosaving in place in any NSDocument subclass in your application does two more things:
• Makes NSDocumentController add a Duplicate menu item to your application's File menu.
• Makes instances of that NSDocument subclass in the responder chain hide the Save As… item in the File menu.

The handling of the user's choosing the Duplicate item is done by three new NSDocument methods:
- (IBAction)duplicateDocument:(id)sender;
- (void)duplicateDocumentWithDelegate:(id)delegate
didDuplicateSelector:(SEL)didDuplicateSelector
contextInfo:(void *)contextInfo;
- (NSDocument *)duplicateAndReturnError:(NSError **)outError;
-duplicateAndReturnError: invokes a new NSDocumentController method to actually create the new document:
- (NSDocument *)duplicateDocumentWithContentsOfURL:(NSURL *)url
copying:(BOOL)duplicateByCopying
displayName:(NSString *)displayNameOrNil
error:(NSError **)outError;
Both of these methods work reliably only when only sent to instances of NSDocument in which autosaving in place is enabled.

When NSDocumentController creates a new duplicate document it sets its name by invoking another new NSDocument method:
- (void)setDisplayName:(NSString *)displayNameOrNil;
If your NSDocument subclass previously implemented this method, you may need to accommodate for NSDocument's implementation and use of this method when you eventually link on Mac OS 10.7. See the comments in <AppKit/NSDocument.h> and <AppKit/NSDocumentController.h> for details.

NSDocument Error Handling Change

The default implementations of some NSDocument methods return recoverable NSErrors. Recovery from some kinds of errors uses resources, like temporary files, that cannot be cleaned up before the NSError is returned. If such an NSError is presented to the user the resource will be cleaned up automatically, regardless of what recovery option the user chooses, but in some rare cases it is not appropriate to present an NSError to the user. In those cases you can trigger the necessary resource cleanup by invoking a new method:
- (void)willNotPresentError:(NSError *)error;
See the comment in <AppKit/NSDocument.h> for details.

File Type Fixing in -[NSDocument saveToURL:ofType:forSaveOperation:completionHandler:]

The new -saveToURL:ofType:forSaveOperation:completionHandler: method has a feature that the old -saveToURL:ofType:forSaveOperation:error: method does not. When the passed-in URL has a file name extension that is not valid for the passed-in type, -saveToURL:ofType:forSaveOperation:completionHandler: internally creates a new URL whose file name extension is valid, and uses that instead for the save operation. It passes that "fixed" URL when it invokes -writeSafelyToURL:ofType:forSaveOperation:error:. If the writing succeeds, it deletes the file located by the original URL. It uses -[NSFileCoordinator itemAtURL:didMoveToURL:] properly when it does this.

This is useful in applications whose documents' types can be changed by user action. For example, in Mac OS 10.7, TextEdit takes advantage of this to more easily convert .rtf files to .rtfd when the user adds attachments to documents.

-saveToURL:ofType:forSaveOperation:error: does not do this. Also, -saveToURL:ofType:forSaveOperation:completionHandler: does not do this when it's invoking -saveToURL:ofType:forSaveOperation:error: for backward binary compatibility.

NSDocumentController Asynchronous Opening and Reopening

Mac OS 10.6 introduced to NSDocumentController the notion of concurrent document opening but no corresponding method was published. In Mac OS 10.7 opening is now done by a new method that does not have to signal success or failure before it returns:
- (void)openDocumentWithContentsOfURL:(NSURL *)url
display:(BOOL)displayDocument
completionHandler:(void (^)(NSDocument *document, BOOL documentWasAlreadyOpen, NSError *error))completionHandler;
Reopening, which is what happens during application launching when AppKit's new Restorable State machinery restores a document that was open when the application was last terminated, is now also done by a new method that does not have to signal success or failure before it returns:
- (void)reopenDocumentForURL:(NSURL *)urlOrNil
withContentsOfURL:(NSURL *)contentsURL
display:(BOOL)displayDocument
completionHandler:(void (^)(NSDocument *document, BOOL documentWasAlreadyOpen, NSError *error))completionHandler;
-openDocumentWithContentsOfURL:display:error: and -reopenDocumentForURL:withContentsOfURL:error:, the old, synchronous, variants of these methods, are deprecated. If your application is overriding one of those methods to customize open or reopening you should override the new method instead. If your application must continue to run on versions of Mac OS X older than 10.7 you can leave your override of the old method there. If you do that then NSDocument will invoke the old method on Mac OS 10.6 and older and the new one on Mac OS 10.7 and newer.

See the comments in <AppKit/NSDocumentController.h> for details.

Move of NSFileWrapper from the AppKit Framework to the Foundation Framework

In Mac OS 10.7 the NSFileWrapper class has been moved from the AppKit framework to the Foundation framework. An NSFileWrapper(NSExtensions) category, declared in <AppKit/NSFileWrapperExtensions.h> remains behind. It includes the -setIcon: and -icon methods. The NSFileWrapper class, including all other methods, is now declared in <Foundation/NSFileWrapper.h>.




NSResponder

- (id)supplementalTargetForAction:(SEL)action sender:(id)sender;
This method is used in the process of finding a target for an action method for both nil target action routing and user interface validation (menus, toolbar items). It allows you to add non NSResponder objects to the action responder chain. Some example uses of this API are: allowing a control's delegate or a plugin to respond to actions.

If this NSResponder instance does not itself respondsToSelector:action, then supplementalTargetForAction:sender: is called. This method should return an object which responds to the action; if this responder does not have a supplemental object that does that, the implementation of this method should call super's supplementalTargetForAction:sender:. NSResponder's implementation returns nil. A basic implementation example:
- (id)supplementalTargetForAction:(SEL)action sender:(id)sender {
    return [_foo respondsToSelector:action] ? _foo : [super supplementalTargetForAction:action sender:sender];
}
Returning an object that does not respond to the action is an error. Generally, this method is called by NSApplication and NSApplication raises an exception in this case.

NSPrintOperation

If the print sheet is unresponsive or sluggish due to the time is takes you to fully render a page, you can check this method in drawRect and other printing methods such as beginDocument and knowsPageRage: to determine if the print operation prefers speed over fidelity. Most applications render each page fast enough and do not need to call this method. Only use this API after establishing that best quality rendering does indeed make the user interface unresponsive.
enum {
// Render at the best quality you can regardless of how slow that may be
NSPrintRenderingQualityBest,
    // Sacrifice the least possible amount of rendering quality for speed
// to maintain a responsive user interface
NSPrintRenderingQualityResponsive
};
typedef NSInteger NSPrintRenderingQuality;
@implementation NSPrintOperation ...
- (NSPrintRenderingQuality)preferredRenderingQuality;
This is an example use of this API:
- (void)drawRect:(NSRect)rect {
NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
if (![currentContext isDrawingToScreen]) {
NSPrintOperation *printOperation = [NSPrintOperation currentOperation]
if ([printOperation preferredRenderingQuality] == NSPrintRenderingQualityResponsive) {
// Render with the best possible quality such that the user interface remains responsive
} else {
// Printing, do a full render
}
}
}

ScrollWheel Events

There are new NSEvent methods to access the scroll wheel event delta that allow for more precise delta values from Magic Mice and trackpads. -deltaX and -deltaY should no longer be used when the event is type NSScrollWheel.

A generic scroll wheel issues rather coarse (line) scroll deltas. That is, the amount that you actually scroll is the line height multiplied by the scroll delta. Some Apple mice and trackpads provide much more precise delta. Instead of multiplying by the line height, you use the scroll delta value as is. The new -scrollingDeltaX/Y methods always return the most precise delta provided by the input device. You can determine precision of the -scrollingDelta with the new -hasPreciseScrollingDeltas method. When -hasPreciseScrollingDeltas returns NO, multiply the returned value by line or row height. When -hasPreciseScrollingDeltas returns YES, scroll by the returned value (in points).
- (BOOL)hasPreciseScrollingDeltas;
- (CGFloat)scrollingDeltaX;
- (CGFloat)scrollingDeltaY;
Touch capable Apple mice and trackpads know when the user physically starts and stops scrolling. AppKit publishes this state using the new method below.
enum {
NSEventPhaseNone = 0, // event not associated with a phase.
NSEventPhaseBegan = 0x1 << 0,
NSEventPhaseStationary = 0x1 << 1,
NSEventPhaseChanged = 0x1 << 2,
NSEventPhaseEnded = 0x1 << 3,
NSEventPhaseCancelled = 0x1 << 4,
};
typedef NSUInteger NSEventPhase;
- (NSEventPhase)phase;
Scroll wheel events issued from non-touch scrolling devices that cannot distinguish when the user starts and ends a scroll gesture have a phase of NSEventPhaseNone. For touch scrolling devices, the first scroll wheel event in the gesture sequence has a phase of NSEventPhaseBegan. Subsequent scroll in the sequence have a phase of NSEventPhaseChanged. When the user physically ends the gesture, the final scroll wheel event has a phase of NSEventPhaseEnded and a scrollingDelta of 0,0.

Some Apple mice and trackpads also issue momentum scroll wheel events. That is, the hardware continues to issue scroll wheel events even though the user is no longer physically scrolling. AppKit routes these scroll wheel events to the view the cursor was over when they started. For custom cells, this may not be enough. Using the new methods below, you can now determine when momentum scrolling starts, continues and stops and further route the events appropriately.
- (NSEventPhase)momentumPhase;
For normal (non momentum) scroll wheel events, the momentumPhase is NSEventPhaseNone. When the hardware switches from user performed scrolls events to momentum scroll wheel events, the momentumPhase is set to NSEventPhaseBegan. Subsequent scroll wheel events from that device have a momentumPhase of NSEventPhaseChanged until the momentum decays to 0, or the user stops the momentum scrolling. The final momentum scroll wheel event has a momentumPhase of NSEventPhaseEnded. All momentum scroll wheel events have a phase of NSEventPhaseNone.


Scroll and Gesture Direction

There is a new user preference to "Move content in the direction of finger movement." To accomplish this, deltaX/Y and scrollingDeltaX/Y are automatically inverted for NSEventScrollWheel events according to the user's preferences. The direction of swipes match the direction of scrolling and, as such, swipe deltas are inverted. However, for some uses of NSEventScrollWheel and NSEventTypeSwipe events, the behavior should not respect the user preference. This method allows you to determine when the event has been inverted and compensate by multiplying -1 if needed.
- (BOOL)isDirectionInvertedFromDevice;

Multi-image dragging

There are new classes and methods to handle dragging. Instead of dragging a single image, you now drag individual images for each item that is in the drag. You can even specify multiple images for each item. These images are then animated into various formations as the user drags. Additionally, the destination of a drop may participate in the drag presentation by setting the images for each item when the user is over the destination.

NSDraggingSource and NSDraggingDestinations are now formal protocols. The following new classes have been introduced. NSDraggingSession, NSDraggingItem, and NSDraggingImageComponent. When a drag is started, an NSDraggingSession is created. The current image based dragging methods are deprecated in favor of new NSDraggingSession based methods (See NSView.h and NSDragging.h). The NSDraggingInfo protocol is expanded with new methods that allow modifications to the drag items. The new NSView method to begin a drag takes an array of NSDraggingItems (pasteboardItems, frames and image providers) and creates the appropriate pasteboard for the drag. The current drag methods on NSWindow and NSView are informally deprecated in favor of this new method.

A basic drag starts by calling -beginDraggingSessionWithItems:event:source: on a view. This new method returns right away and the actual drag occurs later. The caller can take the returned NSDraggingSession and continue to modify its properties such as -animatesToStartingPositionsOnCancelOrFail. When the drag actually starts, the source is sent a -draggingSession:willBeginAtPoint: message followed by multiple -draggingSession:movedToPoint: messages as the user drags. Once the drag is ended or cancelled, the source receives a -draggingSession:endedAtPoint:operation: and the drag is complete.

The destination of a drag works much the same way as before. The draggingEntered:, draggingUpdated:, etc... methods are called at the same times. The sender for these messages still conforms to <NSDraggingInfo>. NSDraggingInfo has some new methods that allow the destination to enumerate the dragging items changing their properties such as frame and image.

When the DragManager determines it is a good time for the drag to change (either formation change and / or image change), the destination is sent an -updateDraggingItemsForDrag: message, if implemented. Waiting for a call to -updateDraggingItemsForDrag: is the preferred way to change the drag image at the right time.


Fluid Swipe Tracking - API

The following API allows for tracking gesture scroll wheel events as a fluid swipe gesture. Similar to iOS, NSScrollView will bounce once if needed, then optionally pass on the gesture scroll wheel events so your controller can use this API to track the scroll gesture as a fluid swipe gesture.

ScrollWheel NSEvents now respond to the -phase message. There are 3 types of scrolls: 1) Gesture scrolls - these begin with NSEventPhaseBegan, have a number of NSEventPhaseChanged events and terminate when the user lifts their fingers with an NSEventPhaseEnded. 2) Momentum scrolls - these have a phase of NSEventPhase none, but they have a momentumPhase of NSEventPhaseBegan/NSEventPhaseChanged/NSEventPhaseEnded. 3) Legacy scrolls - these scroll wheel events have a phase of NSEventPhaseNone and a momentumPhase of NSEventPhaseNone. There is no way to determine when the user starts, nor stops, performing legacy scrolls.

NSScrollView processes all gesture scroll wheel events and does not pass them up the responder chain. Often, tracking a swipe is done higher in the responder chain, for example at the WindowController level. To achieve an iOS style "bounce when not at the edge, otherwise swipe" behavior, you need to inform NSScrollView that it should forward scroll wheel messages when appropriate. Instead of manually setting a property on NSScrollView, your NSResponder can implement the following method and return YES.
- (BOOL)wantsScrollEventsForSwipeTrackingOnAxis:(NSEventGestureAxis)axis;
When the appropriate controller receives a -scrollWheel: message with a non NSEventNone phase, you can call the following message on that event instance to track the swipe or scroll to both user completion of the event, and animation completion.
enum {
NSEventSwipeTrackingLockDirection = 0x1 << 0,
NSEventSwipeTrackingClampGestureAmount = 0x1 << 1
};
typedef NSUInteger NSEventSwipeTrackingOptions;
@interface NSEvent ...
- (void)trackSwipeEventWithOptions:(NSEventSwipeTrackingOptions)options
dampenAmountThresholdMin:(CGFloat)minDampenThreshold
max:(CGFloat)maxDampenThreshold
usingHandler:(void (^)(CGFloat gestureAmount, NSEventPhase phase, BOOL isComplete, BOOL *stop))handler;
...
Below is a pseudo code example of swiping a collection of pictures like the iOS Photo app.
- (BOOL)wantsScrollEventsForSwipeTrackingOnAxis:(NSEventGestureAxis)axis {
return (axis == NSEventGestureAxisHorizontal) ? YES : NO;
}
- (void)scrollWheel:(NSEvent *)event {
// NSScrollView is instructed to only forward horizontal scroll gesture events (see code above). However, depending
// on where your controller is in the responder chain, it may receive other scrollWheel events that we don't want
// to track as a fluid swipe because the event wasn't routed though an NSScrollView first.
if ([event phase] == NSEventPhaseNone) return; // Not a gesture scroll event.
if (fabsf([event scrollingDeltaX]) <= fabsf([event scrollingDeltaY])) return; // Not horizontal
    // If the user has disabled tracking scrolls as fluid swipes in system preferences, we should respect that.
// NSScrollView will do this check for us, however, depending on where your controller is in the responder chain,
// it may scrollWheel events that are not filtered by an NSScrollView.
if (![NSEvent isSwipeTrackingFromScrollEventsEnabled]) return;
    if (_swipeAnimationCanceled && *_swipeAnimationCanceled == NO) {
// A swipe animation is still in gestureAmount. Just kill it.
*_swipeAnimationCanceled = YES;
_swipeAnimationCanceled = NULL;
}
    CGFloat numPhotosToLeft = // calc num of photos we can move to the left and negate
CGFloat numPhotosToRight = // calc num of photos we can move to the right
    __block BOOL animationCancelled = NO;
[event trackSwipeEventWithOptions:0 dampenAmountThresholdMin:numPhotosToLeft max:numPhotosToRight
usingHandler:^(CGFloat gestureAmount, NSEventPhase phase, BOOL isComplete, BOOL *stop) {
if (animationCancelled) {
*stop = YES;
// Tear down animation overlay
return;
}
        if (phase == NSEventPhaseBegan) {
// Setup animation overlay layers
}
        // Update animation overlay to match gestureAmount
        if (phase == NSEventPhaseEnded) {
// The user has completed the gesture successfully.
// This handler will continue to get called with updated gestureAmount
// to animate to completion, but just in case we need
// to cancel the animation (due to user swiping again) setup the
// controller / view to point to the new content / index / whatever
} else if (phase == NSEventPhaseCancelled) {
// The user has completed the gesture un-successfully.
// This handler will continue to get called with updated gestureAmount
// But we don't need to change the underlying controller / view settings.
}
        if (isComplete) {
// Animation has completed and gestureAmount is either -1, 0, or 1.
// This handler block will be released upon return from this iteration.
            // Note: we already updated our view to use the new (or same) content
// above. So no need to do that here. Just...
            // Tear down animation overlay here
self->_swipeAnimationCanceled = NULL;
}
}];
    // We keep a pointer to a BOOL __block variable so that we can cancel our
// block handler at any time. Note: You must assign the BOOL pointer to your
// ivar after block creation and copy!
self->_swipeAnimationCanceled = &animationCancelled;
}



Full Screen

In Lion, we have added support for a fullscreen experience that allows users to run windows in fullscreen mode, where a new space is dynamically created for each window in fullscreen mode. This means for example that you can have a Safari window on the desktop, and another Safari window in a fullscreen space.

NSWindow Full Screen API

An application must specify if a window can enter fullscreen.  Note that existing space-related window collection behaviors continue to have meaning in fullscreen spaces as well. For example, a window with NSWindowCollectionBehaviorTransient will be automatically shown on the fullscreen space if it was visible on the desktop space when you entered fullscreen mode. A window with NSWindowCollectionBehaviorMoveToActiveSpace will be shown in the fullscreen space if the user performs an action to show it, even if it was previously shown on the desktop space. A window with NSWindowCollectionBehaviorManaged stays attached to the space on which it was first shown, as long as it is not closed and reopened.

Windows belonging to other applications will not be allowed on a fullscreen space, except as follows: Windows belonging to a UIElement application are allowed on a fullscreen space. Non-activating panels owned by other applications are also allowed on a fullscreen space, but only if their window collection behavior includes NSWindowCollectionBehaviorFullScreenAuxiliary. Depending on the nature of your window, you may want to include NSWindowCollectionBehaviorCanJoinAllSpaces in the window collection behavior in order to have qualifying windows appear on fullscreen spaces as well as desktop spaces.

enum {
// a window with this collection behavior will have a fullscreen button in the upper right of its titlebar
    NSWindowCollectionBehaviorFullScreenPrimary = 1 << 7,
// windows with this collection behavior can be shown on the same space as the fullscreen window
    NSWindowCollectionBehaviorFullScreenAuxiliary = 1 << 8
};

A window can be taken into or out of fullscreen using -toggleFullScreen:.  If an application supports fullscreen, it should add an "Enter Full Screen" menu item to the View menu.  The menu item is now available through Xcode 4. You can also add the item programmatically, with toggleFullScreen: as the action, nil as the target, and cmd-ctrl-f as the key equivalent. AppKit will automatically update the menu item title as part of its menu item validation.
- (void)toggleFullScreen:(id)sender;
The fullscreen window button is exposed as a standard window button.
enum {
NSWindowCloseButton,
NSWindowMiniaturizeButton,
NSWindowZoomButton,
NSWindowToolbarButton,
NSWindowDocumentIconButton,
NSWindowFullScreenButton
};
typedef NSUInteger NSWindowButton;
A fullscreen window does not draw its titlebar, and may have special handling for its toolbar.  A styleMask is set to indicate that a window has fullscreen appearance.
enum {
    NSFullScreenWindowMask = 1 << 14
};
Notifications are sent for fullscreen changes:
NSString *NSWindowWillEnterFullScreenNotification;
NSString *NSWindowDidEnterFullScreenNotification;
NSString *NSWindowWillExitFullScreenNotification;
NSString *NSWindowDidExitFullScreenNotification;
The window also invokes new delegate methods as appropriate.

NSWindow Delegate Full Screen API

NSWindow invokes the following delegate methods as a window enters and exits fullscreen mode; these give you an opportunity to reconfigure the window layout and perform other operations if necessary.
- (void)windowWillEnterFullScreen:(NSNotification *)notification;
- (void)windowDidEnterFullScreen:(NSNotification *)notification;
- (void)windowWillExitFullScreen:(NSNotification *)notification;
- (void)windowDidExitFullScreen:(NSNotification *)notification;
The default frame of a fullscreen window fills the entire screen (including menuBar and dock areas).  The proposedSize will be a calculated contentSize, leaving space for the toolbar if present.  The window delegate can implement this method to provide a different content size for the window.  The window positioning will be implementation defined (probably centered) if it does not fill the entire screen.
- (NSSize)window:(NSWindow *)window willUseFullScreenContentSize:(NSSize)proposedSize;
The default presentationMode for fullscreen (NSApplicationPresentationFullScreen| NSApplicationPresentationAutoHideDock|NSApplicationPresentationAutoHideMenuBar). A delegate can provide a different set of options to take effect in the space containing this fullscreen window.
- (NSApplicationPresentationOptions)window:(NSWindow *)window
willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions;
The default animation between a window and its fullscreen representation is a crossfade.  With knowledge of the layout of a window before and after it enters fullscreen, an application can do a much better job on the animation.  The following API allows a window delegate to customize the animation by providing a custom window or windows containing layers or other effects.  In order to manage windows on spaces, we need the window delegate to provide a list of windows involved in the animation, in desired z-order, and including the receiver itself if the receiver should stay visible on the fullscreen space. If an application does not do a custom animation, this method can be unimplemented or can return nil.  window:startCustomAnimationToEnterFullScreenWithDuration: will be called only if customWindowsToEnterFullScreen: returns non-nil.
- (NSArray *)customWindowsToEnterFullScreen:(NSWindow *)window;

The system then starts its animation into fullscreen, including transitioning to a new space.  The method below is called to start the window fullscreen animation immediately, and perform the animation with the given duration to  be in sync with the system animation.  This method is called only if customWindowsToEnterFullScreen: returned non-nil.
- (void)window:(NSWindow *)window startCustomAnimationToEnterFullScreenWithDuration:(NSTimeInterval)duration;
In some cases, the transition to enter fullscreen will fail, due to being in the midst of handling some other animation or user gesture.  We will attempt to minimize these cases, but believe there is a need for failure handling.  This method indicates that there was an error, and the application should clean up any work it may have done to prepare to enter fullscreen.  This message will be sent whether or not the delegate indicated a custom animation by returning non-nil from  customWindowsToEnterFullScreen:. Note though that the window will be taken out of the fullscreen space and returned to the desktop even in the failure case, so it is especially important to return any custom animation to the non-fullscreen state in case of error. This is not the case when a failure is encountered while entering fullscreen. In the case of failure to enter, the window is left on the desktop space.
- (void)windowDidFailToEnterFullScreen:(NSWindow *)window;
The following API allows a window delegate to customize the animation when the window is about to exit fullscreen.  In order to manage windows on spaces, we need the window delegate to provide a list of windows involved in the animation, in desired z-order and including the receiver if the receiver should be visible during the animation.  If an application does not do a custom animation, this method can be unimplemented or can return nil.  window:startCustomAnimationToExitFullScreenWithDuration: will be called only if customWindowsToExitFullScreen: returns non-nil.
- (NSArray *)customWindowsToExitFullScreen:(NSWindow *)window;

The system then starts its animation out of fullscreen,  including transitioning back to the desktop space.  The method below is called to start the window animation immediately, and perform the animation with the given duration to  be in sync with the system animation.  This method is called only if customWindowsToExitFullScreen: returned non-nil.
- (void)window:(NSWindow *)window startCustomAnimationToExitFullScreenWithDuration:(NSTimeInterval)duration;
In some cases, the transition to exit fullscreen will fail, due to being in the midst of handling some other animation or user gesture.  We will attempt to minimize these cases, but believe there is a need for failure handling.  This method indicates that there was an error, and the application should clean up any work it may have done to prepare to exit fullscreen.  This message will be sent whether or not the delegate indicated a custom animation by returning non-nil from  customWindowsToExitFullScreen:.
- (void)windowDidFailToExitFullScreen:(NSWindow *)window;

NSApplication Full Screen API

There is a fullscreen presentation option, NSApplicationPresentationFullScreen.   This presentation option is set when in a fullscreen space.

A window delegate may also specify that the window toolbar be removed from the window in fullscreen and auto-shown with the menubar by including NSApplicationPresentationAutoHideToolbar in the presentationOptions returned from -window:willUseFullScreenPresentationOptions:.
enum {
    NSApplicationPresentationFullScreen = (1 << 10),
    NSApplicationPresentationAutoHideToolbar = (1 << 11),
};
typedef NSUInteger NSApplicationPresentationOptions;

Multiple Monitors and Full Screen

We have made some simplifying assumptions for Lion Full Screen behavior on multiple monitors. Multiple monitors are treated as a single unit by Spaces, and therefore are also treated as a single unit in Full Screen. This means that all monitors will be dedicated to windows belonging to the full screen application, and there can be only one primary full screen window visible at a time. A secondary monitor is useful for inspector windows.

Secondly, because the menu bar is located on the main monitor, the primary full screen window will be located on the main monitor as well. This allows the menu bar, floating toolbar, and full screen window to maintain their interrelationship on the same monitor.




Find Bar Support with NSTextFinder

Mac OS 10.7 includes a new class called NSTextFinder that provides a standard Safari-like find bar interface. NSTextFinder also provides incremental search functionality.

NSTextFinder serves as a controller class for the standard Cocoa find bar. NSTextFinder interacts heavily with its 'client', which is an object that provides access to the content being searched and provides visual feedback for a search operation by conforming to the NSTextFinderClient protocol, which will be explained later.


All menu items related to finding (Find…, Find Next, Find Previous, Use Selection for Find, etc.) will have the same action, performTextFinderAction:, which gets sent down the responder chain in the usual way. (Note: Before Mac OS 10.7, the default action for these menu items was performFindPanelAction: which you should update to this new action.) A responder of performTextFinderAction: is responsible for creating and owning an instance of NSTextFinder. Before any other messages are sent to the NSTextFinder, you should set its 'client' property to an object which implements the NSTextFinderClient protocol.


Each user interface item used for finding has a different tag, which corresponds to the appropriate value in the NSTextFinderAction enum (see below). Upon receipt of the performTextFinderAction: message, the responder should call the following on its NSTextFinder instance:
- (void)performAction:(NSTextFinderAction)action;
This method will determine the desired action from the tag and make various callbacks to its client to perform that action. These callbacks are defined in the NSTextFinderClient protocol.

Validation occurs by a similar pattern. The responder should implement validateUserInterfaceItem: and, when the item's action is performTextFinderAction:, it should pass the item's tag to the following method and return the result:
- (BOOL)validateAction:(NSTextFinderAction)action;
This method will also make various callbacks to its clients to determine what the appropriate response should be. These callbacks are also defined in the NSTextFinderClient protocol.


The NSTextFinderAction enum used in the above methods is listed below. The values from this enum are duplicates from the old NSFindPanelAction enum, with the exception of the NSTextFinderActionHideFindInterface value. The NSFindPanelAction values will be mapped to NSTextFinderAction values. Their existing numeric values will be preserved by this mapping.
enum {
NSTextFinderActionShowFindInterface = 1,
NSTextFinderActionNextMatch = 2,
NSTextFinderActionPreviousMatch = 3,
NSTextFinderActionReplaceAll = 4,
NSTextFinderActionReplace = 5,
NSTextFinderActionReplaceAndFind = 6,
NSTextFinderActionSetSearchString = 7,
NSTextFinderActionReplaceAllInSelection = 8,
NSTextFinderActionSelectAll = 9,
NSTextFinderActionSelectAllInSelection = 10,
NSTextFinderActionHideFindInterface = 11,
NSTextFinderActionShowReplaceInterface = 12,
NSTextFinderActionHideReplaceInterface = 13
};
typedef NSInteger NSTextFinderAction;

When an action is performed, NSTextFinder will ask its client for the string it is supposed to search. There are two ways the client can provide this string. It can either implement the -string method, and simply return an NSString, or it can implement the following methods:
- (NSString *)stringAtIndex:(NSUInteger)characterIndex effectiveRange:(NSRangePointer)outRange endsWithSearchBoundary:(BOOL *)outFlag;
- (NSUInteger)stringLength;
These methods make it easier to use NSTextFinder with data that cannot be easily or efficiently flattened into a single NSString. In the first method, the client should return the string which contains the character at the given index in a conceptual concatenation of all strings that are to be searched. For example, if a client had the strings "The quick", " brown fox" , "jumped over the lazy", and "dog", and NSTextFinder requests the string at index 18, then the client should return " brown fox", because the 18th character of all the strings were concatenated together would be the 'x' in "fox". Additionally, the client should return, by reference through the outRange parameter, the effectiveRange of the string that is returned. In the above example, the range of " brown fox" is {9, 10}, because, in the imagined concatenation, the substring starts at index 9 and is 10 characters long.

In some cases, it is not desirable for a match to be found which overlaps multiple strings returned by the above method. For example, suppose a client has a list of names like "John Doe", and "Jane Doe", etc. Normally, if the string is concatenated together like so: "John DoeJane Doe", then a search for "DoeJane" would succeed. To prevent this typically undesirable behavior from happening, the client should return YES, by reference through the outFlag parameter, when returning each individual string. This indicates that there is a boundary between the current string and the next string that should not be crossed when searching for a match.


One of the two approaches described above must be implemented by the client, or else the NSTextFinder will not be able to function. If both approaches (so all three methods) are implemented, stringAtIndex:effectiveRange:endsWithSearchBoundary: will be used by default.


Below are some properties reported by the client for use in NSTextFinder's -validateAction: method. If any of these properties is not implemented, a value of YES will be assumed. Returning NO from any of these methods will disable the actions that require them. For more information about which actions require these properties, consult the NSTextFinder.h header.
@property (getter=isSelectable, readonly) BOOL selectable;
@property (readonly) BOOL allowsMultipleSelection;
@property (getter=isEditable, readonly) BOOL editable;

When an action is sent via -performAction:, NSTextFinder may need additional information from the client to perform that action, or it may require the client to perform some parts of the action on its behalf. The following methods and properties provide the hooks NSTextFinder needs for each of the actions it supports. If the client does not implement one of these methods or properties, then the action that requires it will be disabled.
@property (readonly) NSRange firstSelectedRange;
This property is required for the NextMatch, PreviousMatch, Replace, ReplaceAndFind, and SetSearchString actions. The client just needs to return its first selected range, or {index, 0} to indicate the location of the insertion point if there is no selection.
@property (retain) NSArray *selectedRanges;
This property is required for the ReplaceAllInSelection, SelectAll, and SelectAllInSelection actions. The array should contain NSRanges wrapped in NSValues.
- (void)scrollRangeToVisible:(NSRange)range;
This method is used by many actions, but is not strictly required by any. This method instructs the client to scroll its view to make the given range visible.
- (BOOL)shouldReplaceCharactersInRanges:(NSArray *)ranges withStrings:(NSArray *)strings;
- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)string;
- (void)didReplaceCharacters;
These methods are used by the ShowReplaceInterface, Replace, ReplaceAll(InSelection) and ReplaceAndFind actions. NSTextFinder does not have the ability to directly make changes to the client’s content, so the client is responsible for performing replace operations in these methods. Before a replace operation is performed, NSTextFinder calls the first method to determine if a replacement should take place. If it returns NO, then the given range will not be replaced. If the method returns YES, or is not implemented, then NSTextFinder will call the second method, instructing the client to carry out the replacement. Finally, the third method will be called, if implemented, to indicate that the replacement was completed. For ReplaceAll actions, these methods may be called multiple times, starting from the end of the string and moving toward the beginning, in order to preserve the indexes of the matches which precede the current one.

In order to display the find bar, a "container" for the find bar must be specified. A "container" is an object that conforms to the NSTextFinderBarContainer protocol, described below. You can specify a find bar container using the following property on NSTextFinder:
@property (assign) IBOutlet id <NSTextFinderBarContainer> findBarContainer;
The NSTextFinderBarContainer contains the following methods for displaying and updating the find bar:
@protocol NSTextFinderBarContainer <NSObject>
@required
@property (retain) NSView *findBarView;
@property (getter=isFindBarVisible) BOOL findBarVisible;
- (void)findBarViewDidChangeHeight;
[...]
@end
When a new NSTextFinder is created and instructed to display the find bar, it will create an NSView for the find bar and assign that to the container via the findBarView property. From that point on, the container owns that view and should release it when the container is deallocated. The container should make the find bar visible when the findBarVisible property is set to YES. The container should implement the findBarViewDidChangeHeight method so it can reposition the find bar when its height changes, usually in response to user action.

Important: The container is free to modify the width of the find bar view, but it should never modify its height directly.


Find bar support in AppKit

In Mac OS 10.7, NSScrollView now conforms to NSTextFinderBarContainer in order to support the find bar for any document view searched by NSTextFinder. The find bar can be positioned either above or below the document view by assigning one of the values of the NSScrollViewFindBarPosition enum to the findBarPosition property.

NSTextView also now supports the find bar. The find bar can be enabled or disabled on a text view with the following methods:
- (BOOL)usesFindBar;
- (void)setUsesFindBar:(BOOL)flag;
Only one of usesFindBar and usesFindPanel can be YES at a time. If one value is set to YES, the other will be set to NO.


NSTextFinder Search Feedback

Since Mac OS 10.5, NSTextView has used an animated find indicator to give feedback to the user about a successful find action. The find indicator could be activated manually on an NSTextView via the -showFindIndicatorForRange: method.

To provide this functionality for NSTextFinder clients in Mac OS 10.7, NSTextFinder will show the find indicator at the appropriate time automatically when performing a find. However, NSTextFinder needs to know where to show the indicator and it needs something to draw the text contents of the find indicator. During incremental search, NSTextFinder needs also to know the locations of all the visible matches so it can highlight them as well. The following additions to the NSTextFinderClient protocol provide these capabilities.
@protocol NSTextFinderClient
[...]
@optional
/* This method is used when displaying feedback about find operations to the user.
The client should return the view the contains the character at the given index.
It should also return by reference the entire range of the string displayed by
the view.
*/
- (NSView *)contentViewAtIndex:(NSUInteger)index effectiveCharacterRange:(NSRangePointer)outRange;
/* NSTextFinder uses this method to determine the location to display the find
indicator. The client should convert the given content range to an array of
rectangles in the contentView's coordinate system and return that array. The
given range is guaranteed not to overlap multiple views.
*/
- (NSArray *)rectsForCharacterRange:(NSRange)range;
@end
The first method is called to determine what view the content is displayed in, over which the find indicator will be displayed. Since content may potentially be spread over multiple views (like NSLayoutManager, which supports multiple NSTextViews), the method asks for the view at a given index, and the full range of the string that is contained by that view.

In the second method, the client should determine and return the rectangles in which the content with the given range is displayed in its contentView. The given range is guaranteed not to span multiple content views. The returned rectangles tell NSTextFinder where the matched range is found, so it can show the find indicator there.

NSTextFinder and NSView will handle the find indicator correctly when the contentView is resized, moved, or removed from the view hierarchy. If your content view's scrolling is done by an NSScrollView, the find indicator will also be handled for you during scrolling. Beyond these cases, there may be some circumstances where the find indicator should be immediately cancelled and hidden, such as when the view's content or selection is changed without the knowledge of the NSTextFinder. The find indicator can be cancelled with the cancelFindIndicator method on NSTextFinder listed below. If your document is not scrolled by NSScrollView, then you should set the findIndicatorNeedsUpdate property to YES.

NSTextFinder is responsible for drawing the yellow find indicator background bezel, but the view must provide the contents. NSTextFinder will setup a drawing context and cause the contentView to draw into it. There are two ways this can happen.

NSTextFinder will invoke drawCharactersInRange:forContentView: on its client, if the method is implemented. The client should then draw the requested characters (or ask the containing view the characters, which is provided as a convenience) at the origin of the current context. If the requested character range partially intersects a glyph range, the client may draw the entire glyph, if necessary for performance.

If drawCharactersInRange:ForContentView: is not implemented, then NSTextFinder will use the normal NSView drawing mechanisms. The contentView does not need take any additional action to make this happen.

You should draw the contents of a find indicator slightly differently than normal to make sure it is readable on the background of the find indicator. For example, instead of drawing the text in its original color, it should be black. You can find out when find indicator drawing is occurring by checking the drawingFindIndicator property.


Incremental Search Support with NSTextFinder

A common feature used in conjunction with the find bar is incremental search. This feature allows users to find matches immediately as they are typing. In Mac OS 10.7, NSTextFinder provides this feature for its clients with minimal additional API.

Incremental searching can be enabled by setting the incrementalSearchingEnabled property on NSTextFinder to YES. This property alone is sufficient to cause the NSTextFinder to start searching incrementally.

For improved responsiveness, when a document is sufficiently long, NSTextFinder will search the document in the background. To ensure thread-safety, a client using incremental search must call noteClientStringWillChange on its NSTextFinder before any changes are made to the string provided to the NSTextFinder.

During incremental search, all visible matches are highlighted. NSTextFinder provides two alternatives for highlighting. If your client implements the read-only visibleCharacterRanges property, then by default a gray overlay will appear over your find bar container’s contentView with transparent "holes" cut out for each match. This contentView should be a superview of all contentViews reported by the NSTextFinderClient. NSScrollView already implements this property, so you only need to implement this property when using a different container class. Finally, this mode also requires the same two NSTextFinderClient methods that are used to display the find indicator: contentViewAtIndex:effectiveCharacterRange: and rectsForCharacterRange:. However, the implementation of these methods is identical for both purposes, so no additional work is required to support incremental search.

To disable the overlay, you should set the incrementalSearchingShouldDimContentView property to NO. If you do, you can still show matches from incremental search by using the NSTextFinder’s incrementalMatchRanges property. This property is an array of ranges specifying all incremental matches found so far. The array is updated on the main thread while the incremental search is performed on a background thread. You may use Key Value Observing to receive notifications when the contents of this array changes. If you use NSKeyValueObservingOptionNew and NSKeyValueObservingOptionOld, the dictionary passed to the KVO notification method will provide the indexes and ranges that are added or removed.

You may use the incrementalMatchRanges array to display the matches however you choose, but if you choose to highlight them in your view, it is recommended that you use the drawIncrementalMatchHighlightInRect: method to draw the standard highlight.


Incremental Search Support in NSTextView

In Mac OS 10.7, NSTextView provides incremental search support. It is disabled by default, but it can be enabled by setting the incrementalSearchingEnabled property to YES. Also, since incremental searching requires the find bar, usesFindBar must be set to YES for incremental searching to be occur.


NSCollectionView Drag and Drop Click-and-hold Delay

When NSCollectionView gained drag and drop support in Mac OS 10.6, a click-and-hold delay was required to differentiate drag and drop from drag selection. This is still the case in Mac OS 10.7 for collection views that support multiple selection. However, since drag selection is not important for single-selection collection views a click-and-hold delay is no longer required to start a drag and drop operation in applications linked on or after Mac OS 10.7.


NSCollectionView Multi-image dragging

NSCollectionView now supports multi-image dragging.

To support multi-image dragging for a dragging source, all you need to do is implement -collectionView:pasteboardWriterForItemAtIndex:. NSCollectionViewItem is responsible for creating dragging image components. You can customize its default behavior by overriding -draggingImageComponents. You can customize dragging session settings like draggingFormation or animatesToDraggingFormationOnBeginDrag by implementing -collectionView:draggingSession:willBeginAtPoint:forItemsAtIndexes:. You can also be informed when dragging ends by implementing -collectionView:draggingSession:endedAtPoint:dragOperation:.

More work is required to support multi-image dragging for dragging destinations. First of all, you need to make sure your acceptDrop: method uses the new item-based NSPasteboard APIs. Some time after a multi-image drag enters your collection view, -collectionView:updateDraggingItemsForDrag: is called on the delegate. Within that method you should enumerate the dragging info's dragging items and do the following:

1. Map the NSDraggingItem's item to a representedObject for your collection.
2. Create a new NSCollectionViewItem with the represented object. (The collection view item is typically created by copying the itemPrototype. Also, you may create a single collection view item and reuse that for each NSDraggingItem.)
3. Determine the target frame size for the item and set the NSDraggingItem's frame size.
4. Update the NSDraggingItem's image components provider using the frame from (3) and NSCollectionViewItem's -draggingImageComponents (or other custom code for generating the image components).

NSCollectionView's subview layout is dependent on the number of items contained in the collection. The method -frameForItemAtIndex: is based on the number of items currently contained in the collection. Since drag and drop operations typically change the number of items in the collection, you will likely need to use the new -frameForItemAtIndex:withNumberOfItems: method to compute the proper frame sizes.

To make the dragged images animate to their final destinations, you can set the draggingInfo's animatesToDestination property in your delegate's implementation of validateDrop:. If you do, you should enumerate the dragging info's dragging items in acceptDrop: and update them with their proper frames. Be sure to update your collection view's or array controller's content synchronously in acceptDrop: to get the proper animations.



NSDocument Autosaving In Place – Unintentional Edits and Versions Browser

NSDocument's "Autosaving In Place" eliminates the largely unnecessary user task of manually saving documents. However, when saving happens without user knowledge, it becomes easier for unintentional edits to get saved to disk. To help avoid this problem, when an NSDocument subclass adopts autosaving in place by returning YES from +autosavesInPlace, it will use various heuristics to determine when a user may have opened a document with the intention to read, but not edit it. When such a file is opened, NSDocument will warn the user when an edit is made to the document, offering them the choice of canceling the change, creating a new document with the change, or allowing editing, if possible. A document that is preventing edits will display "Locked" in the right-hand corner of the title bar. If the user intends to edit the document, they can avoid the alert by clicking on the "Locked" text and allowing editing by choosing "Unlock" in the pop-up menu. A document that has been changed since it was last opened and is therefore being actively autosaved in place will show "Edited" in the titlebar instead of "Locked".

Sometimes a user may choose to edit a file, then decide to revert those changes later. While a user is working on an autosaved in place document, NSDocument will, at various times, preserve the current contents of the document to disk. The user can access these preserved versions by selecting "Revert to Saved" from the File menu, or by selecting "Browse All Versions…" from the menu available in the right-hand corner of the document window's title bar. This brings the user into an interface that displays both the current document and a "stack" of previous versions. If the user chooses to restore a previous version, the current document contents are preserved on disk, if necessary, and the file's contents are replaced with those of the selected version. By holding the Option key, the user can also choose to restore a copy of a previous version, which will not affect the current document contents. Since old document versions are live windows, the user can also select and copy contents from them and paste them into the current document. Since the version browser interface takes control of the entire screen, you can set the NSDocumentRevisionsDebugMode user default to YES for easier debugging of your application in this interface.

Mac OS 10.7 includes several APIs to allow your application to customize its behavior in the version browser. First of all, the window that is used in the version browser is determined by the -windowForSheet API. You may also wish to simplify application's interface when the user is viewing old document versions. You can detect when to do this by checking the -isInViewingMode method on NSDocument. This value is set to YES before your the interface is loaded for an old document version. If you wish to change the interface of the current document when it enters or exits the version browser you can use the NSWindowDelegate methods, -windowWillEnterVersionBrowser: and -windowDidExitVersionBrowser:, or their NSNotification equivalents.

In order to fit two document windows side-by-side, the version browser may attempt to resize and/or scale the windows. When a window is scaled down the user can click on it to bring it back to full size. You can control the size of your document window in the version browser by implementing the -window:willResizeForVersionBrowserWithMaxPreferredSize:maxAllowedSize: method. The returned size will be used to determine the resulting size of the document windows in the version browser. You may return any size from this method, but that size is constrained to the "maximum allowed size" to ensure the version browsing controls are still accessible. If the window is larger than this size and cannot be resized, an exception will be thrown. The "maximum preferred size" parameter specifies the largest size a window can be without requiring scaling. If this method is not implemented, the version browser will use -window:willUseStandardFrame: to determine the resulting window frame size.


NSDocument File Dependence

When an NSDocument's file disappears from the file system the document can usually continue to function properly and even allow the user to re-save it if the entire file has been loaded into memory. When this happens with a file that has not been completely loaded, then unexpected errors may occur. NSDocument has a new method in Mac OS 10.7 called -isEntireFileLoaded, which is intended to provide explicit knowledge about a document's dependence on its file. NSDocument may use this information to do things like prevent volume ejection or warn the user when a partially loaded file disappears from the file system.

NSDocument's base implementation of this method returns YES, providing the same default behavior as before Mac OS 10.7. If you override -readFromURL:ofType:error: or -readFromFileWrapper:ofType:error: and read only a portion of the file or file wrapper, you should override -isEntireFileLoaded and return NO. If at some point the entire file is completely loaded, then you can start returning YES. Similarly, if portions of the file are removed from memory, you should start returning NO again.


NSSplitView Restorable State

In Mac OS 10.7, NSSplitView will participate in automatic state restoration by persisting its subview's frames, and restoring them when the app launches. If necessary, this process will invoke the same NSSplitViewDelegate methods used for constraining divider positions to ensure proper layout. For compatibility reasons, an NSSplitView will not participate in Mac OS 10.7's automatic state restoration unless it is assigned an autosave name. You can set the autosave name in Interface Builder, or in code using the -setAutosaveName: method.




Changes for @2x images

10.7 contains some changes to accommodate the iOS naming convention for high resolution images. If your bundle contains files named foo.png, foo@2x.png, and foo.pdf then [NSImage imageNamed:@"foo"] will return an NSImage backed by all three files, provided your app is linked against the 10.7 SDK.

This accomplishes something similar to how iOS handles hi-res images, but the mechanics are a little bit different. On iOS it's known at device startup whether @2x images are appropriate. On Mac OS X, the machine might go to sleep and wake up with a different screen attached. On iOS [UIImage imageNamed:@"foo"] loads foo.png if you are running on an iPhone 3Gs, and it loads foo@2x.png if you are running on an iPhone 4. On the mac, [NSImage imageNamed:@"foo"] unconditionally returns an NSImage object that contains three NSImageRep objects, one for each of foo.png, foo@2x.png, and foo.pdf. Each time the NSImage is drawn, it selects the representation best for the drawing context.

That takes care of +[NSImage imageNamed:], but +imageNamed: only finds resources in the main app bundle, not in frameworks or plugins. Framework authors typically do something like this:
   [[NSImage alloc] initByReferencingURL:[pluginBundle URLForImageResource:@"foo"]]
…which can only pick up one of foo.png, foo@2x.png, and foo.pdf since the URL is explicit. To provide a way forward, we add a one step method to get an image:
    @interface NSBundle(NSBundleImageExtension)
    - (NSImage *)imageForResource:(NSString *)name NS_AVAILABLE_MAC(10_7);
    @end
This can return an NSImage backed by multiple files, and it can also automatically call setTemplate: when appropriate according to the template image naming convention used in +imageNamed:.

Despite NSImage having this multifile support, we don't really expect you to use it much. If you have resources foo.png and foo@2x.png in your project resources, Xcode is going to roll them together into a multi-representation foo.tiff that contains both during build. NSImage has always had support for reading TIFF files with multiple image representations.

Performance note: NSImage has laziness in instantiating images. [NSImage imageNamed:] does no file IO at all, provided bundle contents are already cached. When you draw an image, we read the header of each backing file in order to see how large each is and select the best one given the drawing context. However, we avoid decoding the image data for a representation that is never selected. If you let Xcode assemble your images into a single TIFF, there's only one file whose header we have to read.

Bug in deprecated -[NSImage composite…] methods fixed conditional on linking with 10.7 SDK

We don't mention every bug fix in the release notes, but we do try to mention every time we do something that has behavior conditional on the SDK you link with. I say this to explain why this rather complicated section is here. If you don't use the deprecated -composite… methods, you can skip to the next section.

For 10.6, we rewrote the internals of NSImage, and fixed a lot of bugs and strangenesses. As part of that, we deprecated all the NSImage methods that start with composite, because they have surprising semantics as compared to the methods that start with draw. Since the -composite… methods were being deprecated, we didn't try to change their behavior and correct bugs in places where the fixes might mess up apps depending on the bugs.

However, the -composite… methods are used in really a lot of extant code, despite being deprecated. And one bug that we were aware of messes up a lot of applications when running at HiDPI, even if they're okay at 1.0x.

So, we fixed the bug, conditional on the app either being run at HiDPI or on it being linked against the 10.7 SDK or greater.

The bug is that -[NSImage compositeToPoint:fromRect:operation:fraction:] interpreted the fromRect in the coordinates of the NSImageRep selected to draw with instead of in the coordinates of the NSImage.

The symptom is that instead of a whole image at the correct size, you see just a corner, blown up, or you see the image too small. If you hit this, switch to one of the NSImage methods that start with -draw… (and also fix the fromRect, since it's probably wrong).


Cocoa Autolayout

10.7 introduces a new system for layout, reworking the springs and struts model. So big it needs its own release note!




NSApplication and Apple Push Notifications

NSApplication can register to receive push notifications similar to UIApplication on iOS. Currently, only badge notifications are supported on Mac OS X for non-running applications. Running applications can interpret data from the push server as desired.

To register to receive push notifications, use:
- (void)registerForRemoteNotificationTypes:(NSRemoteNotificationType)types;
If successful, the application’s delegate will receive a callback message with an opaque data blob representing the token used to communicate with the Apple Push Notification server (read the documentation on Push Notifications for more details on that interaction). If the application is not open when a push notification is received, the notification information is delivered in the userInfo dictionary for the NSApplicationDidFinishLaunchingNotification notification using the key NSApplicationLaunchRemoteNotificationKey. If the application is open when a push notification is received, the delegate gets a application:didReceiveRemoteNotification: message.


Button Appearance Changes

As part of an ongoing refresh of Aqua in Mac OS X Lion, some buttons look different and may not look the same in every context in your application. Specifically, the “Round Textured” button is not appropriate in any context other than directly on the background of a textured window. If you are using this kind of button in a table view or other context, please consider changing it to a “Round Rect” button.



NSPasteboard data-reading methods

The documented behavior of NSPasteboard has historically required that -types or -availableTypeFromArray: be sent to a pasteboard before invoking the data-reading methods -dataForType:, -propertyListForType:, and -stringForType:. Beginning in the 10.6 (the previous release of Mac OS X), calling these data-reading methods perform an implicit check for the requested type before attempting to read the data, making it no longer strictly required to call -types or -availableTypeFromArray: before calling the data-reading methods.

NSPasteboard UTI and Scrap Manager/Drag Manager Interoperability

As applications move towards using UTIs with NSPasteboard, as opposed to pboard types, an application may still need to interact with existing applications which use four character OS types with the legacy Scrap Manager and Drag Manager.

To interoperate with these legacy types, use the functions declared in UTTypes.h to generate the appropriate UTI string for a given OSType. The code below generates the appropriate UTI from a fictional OS type 'test':
CFStringRef flavorString = UTCreateStringForOSType('test');
CFStringRef conformsToType =  (floor(NSAppKitVersionNumber) <=  NSAppKitVersionNumber10_5) ? NULL : kUTTypeData;
CFStringRef utiForConvertedScrapFlavor = UTTypeCreatePreferredIdentifierForTag(kUTTagClassOSType, flavorString, conformsToType);
// Use the utiForConvertedScrapFlavor
CFRelease(flavorString);
CFRelease(utiForConvertedScrapFlavor);
Using the generated UTI to read and write pasteboard data allows your application to interoperate with legacy Scrap Manager and Drag Manager clients.

Two things to note about the code sample:

1. The AppKit version check is required because of a change in behavior between 10.5 and 10.6. All UTIs used on the pasteboard should conform to kUTTypeData, but in 10.5 UTIs generated internally by NSPasteboard did not. This was addressed in 10.6. The version check ensures that the UTI string generated in your code will match the UTI that will appear on the pasteboard for that release. If your application will ship only on 10.6 and later, you can remove the version check and use kUTTypeData as the last argument to UTTypeCreatePreferredIdentifierForTag().

2. Always generate the UTI dynamically from the OSType. Do not store or cache the UTI string between application launches. This will ensure your pasteboard code continues to work, even if the developer of the legacy application releases a new version at a later date that formally maps the legacy OSType to a declared UTI string, or if the algorithm for generating dynamic UTIs changes in a future OS release.



Additional NSPasteboard Exceptions Added

NSPasteboard and NSPasteboardItem have methods to set NSData, NSString, and property list values. Classes that implement the NSPasteboardWriting protocol also provide property list values. Prior to 10.7, setting or providing an object of the wrong class, or invalid property lists, would fail silently. For applications linked on or after 10.7, this programming error now causes an exception to be raised.



Accessibility

When an accessibility client sets the AXSelectedRows and AXSelectedColumns of NSTableView, the behavior now correctly mirrors user selection of rows and columns, including invoking appropriate delegate methods such as -tableView:tableViewselectionIndexesForProposedSelection:.

NSScroller no longer reports accessibility children when its subelements are not visible.

NSSecureTextField now reports its caps lock and num lock indicators as AXImage accessibility children, if they are visible.

NSRulerView now posts NSAccessibilityUnitsChangedNotification when its measurement units change.

Accessibility of View-Based NSTableView and NSOutlineView

Mac OS X 10.7 adds support for using NSViews instead of NSCells to define the contents of table and outline views. View based table and outline views automatically provide a richer and more complete representation to accessibility. This is because complex table interfaces can now be represented as a composition of standard AppKit views and controls, such as text fields and image views, instead of custom cell subclasses. This allows a view-based table or outline to take advantage of the built-in accessibility of AppKit views and controls, removing the need for custom accessibility code to support complex cell subclasses.

View-based table views are reported to accessibility as using AXCells as the children of its rows. (Despite the similar terminology, an AXCell has no relationship to an NSCell). This means that changing an existing table view or outline view to be view-based will require AppleScript-based or AX-based user interface automation scripts to be updated to handle the new structure.

Accessibility and table cell views

The NSTableCellView class has a built-in 'textField' outlet and property. You should connect this outlet to the main text field in the cell. This text field will be automatically reported as the title UI element of the cell. Connecting this outlet greatly enhances the usability of the table for VoiceOver users, especially when the cell contains multiple pieces of information, such as additional subordinate pieces of information.

If you use a table cell view which is not a subclass of NSTableCellView, adding a 'textField' outlet and property is strongly recommended. AppKit treats 'textField' as a special key for any table cell view, and reports the value of that property as the title UI element of the table cell.

Changes to behavior of NSAccessibilityPostNotification()

In 10.7 NSAccessibilityPostNotification() checks for accessibility client observers differently depending on the notification. See NSAccessibility.h for a detailed description of the behavior changes.

NSPopover Accessibility

Popovers displayed using the new NSPopover class report themselves to accessibility clients using the new NSAccessibilityPopoverRole constant in NSAccessibility.h.

The accessibility parent of a popover is the user interface element that the popover popped from. Because an NSView subclass can have accessibility subelements, AppKit uses a heuristic to determine the correct accessibility parent for a popover, treating that element as the popover's parent, and temporarily making the popover a child of that element while the popover is visible.

If you need to override AppKit's default assignment of the popover's accessibility parent, override -accessibilityAttributeValue: in an NSPopover subclass to return a different object that implements NSAccessibility.

Accessibility and Automatic Termination

For All AppKit Applications:
After an accessibility client, such as VoiceOver, has made an accessibility request to an application, automatic termination will be disabled for that application to ensure that accessibility clients can continue to access the same application process.  Because accessibility clients such as GUI Scripting are also used for automated testing during application development, setting the user default NSDisableAutomaticTerminationAfterAccessibilityRequest to NO will override the default behavior so that these automated tests can be run without automatically disabling automatic termination.

For Assistive Applications Only:
If your application is an accessibility client (i.e. those that use the AX APIs found in the HIServices framework to interact with other applications), you should consider how your application uses the AX APIs when planning to enable Automatic Termination in your application.  For example, if your application needs to respond to accessibility notifications, even when it is hidden, you should disable automatic termination.  On the other hand, if your application displays information about the UI element under the mouse, but does not make accessibility requests when hidden, the usage of AX APIs would not prevent you from enabling automatic termination. See the documentation for more details on Automatic Termination itself.

Accessibility and Overlay Scrollers

An overlay scroller reports the AXHidden attribute to indicate if it is currently hidden or visible. This attribute is settable. An assistive application can set this value to 'NO' to make the scroller visible temporarily. Note that 'NO' is the only valid value, visible scrollers cannot be forced to be hidden with a value of 'YES'.



Press-and-Hold for Certain Keys

A new system-wide behavior has been implemented for cases in which the user presses and holds down certain keys while editing text. Instead of repeating the key, this new behavior provides a mechanism for entering alternative (usually accented) forms. UI appears near the text showing these alternative forms, which can be selected by clicking, by arrowing, or by pressing a digit corresponding to the index of the desired form. Keys other than letter and digit keys continue to repeat when pressed and held.

This new behavior generally should be active only in cases in which text is actually being edited, but there are a few cases in which it may need to be turned off explicitly. There is a default provided for this, ApplePressAndHoldEnabled, which may be set to NO to turn off the new press-and-hold behavior and re-enable key repeat for all keys. This may be set for a specific application, to control the behavior for that application only, or globally, to control the behavior for all applications.


Additional API for Autocorrection

There is new API on NSSpellChecker for supporting autocorrection. First, there is now a convenience method that allows separate access to correction results, which otherwise had been available only via the unified text checking methods checkString:range:types:options:inSpellDocumentWithTag:orthography:wordCount: and requestCheckingOfString:range:types:options:inSpellDocumentWithTag:completionHandler:.
- (NSString *)correctionForWordRange:(NSRange)range
inString:(NSString *)string
language:(NSString *)language
inSpellDocumentWithTag:(NSInteger)tag;
Second, there is now API to allow clients to report the user's response to a proposed correction, so that the spell checker can learn from this and adjust future correction behavior accordingly. This is used by views such as NSTextView and WebView, and third parties implementing their own text editing views that support autocorrection can use it as well. The tag, language, word, and correction should match those from the original correction result, so that the spellchecker can match them. This implies that in order to record responses properly, clients must store the original word and original correction at least from the point at which the user accepts it until the user edits or reverts it.
enum {
NSCorrectionResponseNone, // No response was received from the user
NSCorrectionResponseAccepted, // The user accepted the correction
NSCorrectionResponseRejected, // The user rejected the correction
NSCorrectionResponseIgnored, // The user continued in such a way as to ignore the correction
NSCorrectionResponseEdited, // After the correction was accepted, the user edited the
// corrected word (to something other than its original form)
NSCorrectionResponseReverted // After the correction was accepted, the user reverted the
// correction back to the original word
};
typedef NSInteger NSCorrectionResponse;
- (void)recordResponse:(NSCorrectionResponse)response
toCorrection:(NSString *)correction
forWord:(NSString *)word
language:(NSString *)language
inSpellDocumentWithTag:(NSInteger)tag;
Third, there is now API to allow clients to bring up the new UI for autocorrection. This is also used by views such as NSTextView and WebView, and third parties implementing their own text editing views that support autocorrection can use it as well. This user interface is used to indicate a correction intended to be made, allowing the user to accept or reject it; or once a correction has been made, to indicate the original form, allowing the user to revert back to it; or to display multiple alternatives from which the user may choose one if desired. The primaryString is the first string displayed, a correction or reversion according to the type of indicator; the alternativeStrings should be additional alternatives, if available. Only one indicator at a time may be displayed for a given view, and the only thing a client may do with the indicator after displaying it is to dismiss it. When an indicator is dismissed, whether by user action or by the view, the completion block will be called, with the acceptedString argument being either the replacement string accepted by the user, or nil if the user has not accepted a replacement.
enum {
NSCorrectionIndicatorTypeDefault = 0, // The default indicator shows a proposed correction
NSCorrectionIndicatorTypeReversion, // Used to offer to revert to the original form after a correction has been made
NSCorrectionIndicatorTypeGuesses // Shows multiple alternatives from which the user may choose
};
typedef NSInteger NSCorrectionIndicatorType;
- (void)showCorrectionIndicatorOfType:(NSCorrectionIndicatorType)type
primaryString:(NSString *)primaryString
alternativeStrings:(NSArray *)alternativeStrings
forStringInRect:(NSRect)rectOfTypedString
view:(NSView *)view
completionHandler:(void (^)(NSString *acceptedString))completionBlock;
- (void)dismissCorrectionIndicatorForView:(NSView *)view;
Finally, there is additional API to support the new global user preference settings for automatic text replacement and spelling correction. NSTextView now by default will keep track of and follow these settings automatically, but applications using NSTextView can override that by programmatically using existing NSTextView methods such as -setAutomaticTextReplacementEnabled: and -setAutomaticSpellingCorrectionEnabled: to control an individual text view's settings. The new API is primarily for non-text view clients who wish to keep track of the settings for themselves, using the NSSpellChecker class methods to determine their values, and optionally also notifications to determine when the settings have changed.
+ (BOOL)isAutomaticTextReplacementEnabled;
+ (BOOL)isAutomaticSpellingCorrectionEnabled;
NSString * const NSSpellCheckerDidChangeAutomaticSpellingCorrectionNotification;
NSString * const NSSpellCheckerDidChangeAutomaticTextReplacementNotification;

Regular Expression Text Checking

There is an additional key, NSTextCheckingRegularExpressionsKey, to be used in the options dictionary with the unified text checking methods checkString:range:types:options:inSpellDocumentWithTag:orthography:wordCount: and requestCheckingOfString:range:types:options:inSpellDocumentWithTag:completionHandler:. This key allows clients to specify a set of regular expressions to be searched for during text checking. Results will be reported using NSTextCheckingResults of type NSTextCheckingTypeRegularExpression. There are no default actions provided in response to these results, but clients may in this way detect the occurrence of particular regular expressions in text, in somewhat the same way that Data Detectors currently detects addresses, phone numbers, etc., and take any desired action in response.



NSTableView / NSOutlineView General Updates

Tables/Outlines setup as a source list (identified by the selectionHighlightStyle of NSTableViewSelectionHighlightStyleSourceList) on 10.7 and higher will now only allow a drag to begin from "content" in the cells. This is determined by using the NSCell methods hitTestForEvent:inRect:ofView: and returning NSCellHitContentArea.

Since Leopard, NSTableView has supported full width cells (which span all columns) by returning a cell from tableView:dataCellForTableColumn:row: when a 'nil' tableColumn is passed in. Up until Lion, NSTableView would incorrectly pass a non-nil value to the tableColumn parameter when the user right clicked on a row. This has been fixed for Lion linked applications, but prior applications will need to work around this by returning the proper cell even though a column was passed to the tableView:dataCellForTableColumn:row: method.

In 10.7 and higher tables that support variable row heights now have the row height values returned from -tableView:heightOfRow: cached by the NSTableView/NSOutlineView until noteHeightOfRowsWithIndexesChanged: (or reloadData) is called. Applications targeting 10.6 or lower need to ensure the implementation always returns the same value for the same row (as it may be called multiple times for the same row) until noteHeightOfRowsWithIndexesChanged: / reloadData is called.

Allowing column selection ( [tableView setAllowsColumnSelection:YES]) combined with the "none" selection highlighting style (NSTableViewSelectionHighlightStyleNone) would previously cause a crash when selecting a row after selecting a column. This has been fixed for applications that link on 10.7 or higher. Applications targeting 10.6 or lower should turn off column selection with [tableView setAllowsColumnSelection:NO].

Calling [tableView setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleSourceList] will have the side effect of changing the backgroundColor to the standard "source list" color, and setting the draggingDestinationStyle to be NSTableViewDraggingDestinationFeedbackStyleSourceList. This allows one to easily setup a "source list" style NSTableView or NSOutlineView. For applications linked less on an OS lower than 10.7, calling setSelectionHighlightStyle to anything else would change the backgroundColor to [NSColor controlBackgroundColor] and draggingDestinationStyle to NSTableViewDraggingDestinationFeedbackStyleRegular. 10.7 now correctly only does this change if the previous style was a source list.

NSTableView now has a new rowSizeStyle property. This is mainly for sidebars/source lists to have a consistent layout defined by the Human Interface Guidelines. Setting the rowSizeStyle to NSTableViewRowSizeStyleCustom causes the table to behave as it always has. For any other value, the table will automatically change the -rowHeight based on various options; for instance, group rows may have a smaller row height than non-group rows. When the rowSizeStyle is not NSTableViewRowSizeStyleCustom, the -rowHeight will return the standard row height for non-group rows. Variable row heights can still be used; it is recommended to return the -rowHeight when a default height is needed, but group rows will require a custom specific row height to be returned (i.e.: 20). View Based TableViews should use NSTableCellView -- it will automatically layout the textField and imageView based on the current rowSizeStyle, and apply appropriate "sidebar / source list" attributes to the textField's stringValue and imageView's image.

NSTableView / NSOutlineView - View Based TableView and Animations

NSTableView and NSOutlineView in Mac OS 10.7 now support the use of NSViews instead of NSCells. Search for "View Based" in NSTableView.h, NSOutlineView.h for more information, and see: NSTableRowView.h and NSTableCellView.h.

NSTableView and NSOutlineView now have methods to insert/remove/move rows and items, optionally with an animation. These methods work for both the "Cell Based" and "View Based" NSTableView/NSOutlineView, however, the "Cell Based" version must always call -beginUpdates before doing any insert/remove/move calls, and then end with an -endUpdates. This allows the NSTableView to capture the current state to perform animations. You must not make changes to your model until after -beginUpdates has called, and you must update your model before -endUpdates is called.

NSTextFields inside a View Based TableView may have the -backgroundColor automatically changed when editing. Specifically, if an NSTextField is not bordered (isBordered==NO && isBezeled==NO), and does not draw a background (drawsBackground==NO), then NSTableView will automatically make the -backgroundColor be white, and set to be drawn, when it is editing (ie: when it is the firstResponder). This helps provide a complete Table View experience for the end user.

The NSTableRowView is responsible for drawing the bottom line of a horizontal grid if the gridStyleMask has NSTableViewSolidHorizontalGridLineMask set. This will happen automatically. However, the TableView draws any grid lines below the last row with drawGridInClipRect:. Subclassing drawGridInClipRect: is still acceptable, but horizontal grid lines should only be drawn past the last row. Vertical grid lines are currently not customizable.

Note that the View Based TableView does not support column selection.

The View Based NSTableView supports animating selection changes. This can be done using the animator proxy and calling -selectRowIndexes:byExtendingSelection:, such as: [[tableView animator] selectRowIndexes:indexes byExtendingSelection:NO];

NSTableView now implements -cancelOperation: to allow escape to automatically cancel text editing. This is accomplished by calling -abortEditing on the NSControl that is showing the current field editor. This action can be customized by overriding -cancelOperation: on NSTableView or overriding -abortEditing on the control that exists in the View Based TableView.

To disable animations, create an animation group around the code you want them to be disabled for and set the duration to 0. IE:
[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:0];
...
[NSAnimationContext endGrouping];

Syncing Animations with NSTableView

The following NSTableView methods can animate:
- (void)insertRowsAtIndexes:(NSIndexSet *)indexes withAnimation:(NSTableViewAnimationOptions)animationOptions;
- (void)removeRowsAtIndexes:(NSIndexSet *)indexes withAnimation:(NSTableViewAnimationOptions)animationOptions;
- (void)moveRowAtIndex:(NSInteger)oldIndex toIndex:(NSInteger)newIndex;
- (void)noteHeightOfRowsWithIndexesChanged:(NSIndexSet *)indexSet; // View-based tableview only
There may be a need to sync animations that happen inside the view, or with other things outside of the Table. This can be done by surrounding the calls with a specific NSAnimationContext grouping that already has a specific duration set. See the TableViewPlayground demo app for an example. In addition, if the duration is 0, then no animation will happen.

NSTableView / NSOutlineView Multi-image Dragging

NSTableView and NSOutlineView now support multi-image dragging. NSOutlineView methods mirror the NSTableView ones, but use 'item' instead or 'row. There are two components to dragging; being a dragging source and a dragging destination.

For a dragging source, the dataSource should implement tableView:pasteboardWriterForRow: and return an object that implements NSPasteboardWriting. That is all that is required to be a source. However, dataSource hooks are also provided for when the dragging session begins (tableView:draggingSession:willBeginAtPoint:forRowIndexes:) and ends (tableView:draggingSession:endedAtPoint:operation:). To control the drag image, the NSCell method draggingImageComponentsWithFrame:inView: is called on the clicked cell. For View Based TableViews, NSTableCellView's draggingImageComponents should be used, and can be overridden to customize the drag image.

The default implementation of NSCell's draggingImageComponentsWithFrame:inView: will generate an image from the cell and return two components: one for NSDraggingImageComponentLabelKey and another for NSDraggingImageComponentIconKey. This is done by capturing the portion from titleRectForBounds: and imageRectForBounds: respectively.
NOTE: NSCell currently has an issue where it will return an empty array from draggingImageComponentsWithFrame:inView: if the cell does not have an image portion. To work around this, subclass NSCell and override draggingImageComponentsWithFrame:inView: and generate your own NSDraggingImageComponents in the returned array.

To be a dragging destination, more work is required than to be a source. Implement tableView:updateDraggingItemsForDrag: to provide a drag image representation for the source content that was dragged over the tableView. Generally, this involves using a template NSCell and calling the new NSCell method draggingImageComponentsWithFrame:inView:. For View Based TableViews, NSTableCellView's draggingImageComponents should be used. tableView:validateDrop:proposedRow:proposedDropOperation: should be implemented as normal. In tableView:acceptDrop:row:dropOperation one should enumerate the NSDraggingInfo's classes and create new model objects. The table should be told of the changes by doing an insertRowsAtIndexes:withAnimation: using the animation option NSTableViewAnimationEffectGap to create a gap for the dragged image. The NSDraggingItem's draggingFrame should be updated to the appropriate -frameOfCellAtColumn:row:.

See the DragNDropOutlineView (cell based) and TableViewPlayGround (view based) examples for more information.

Implementing Sidebar Source Lists with NSOutlineView

The proper way to create a source list sidebar is to use NSOutlineView. The rowSizeStyle should be set to NSTableViewRowSizeStyleDefault, and all three sizes should be tested. Items which should not be expandable or collapsable by the user can have the outline cell hidden by using the delegate method outlineView:shouldShowOutlineCellForItem:. These items should be programmatically expanded. Group header items are created by using the delegate method outlineView:isGroupItem: and returning YES. To find out what rowSizeStyle the system is using, you can call [tableView setRowSizeStyle:NSTableViewRowSizeStyleDefault] and then read the current value with: [tableView effectiveRowSizeStyle]. This will return NSTableViewRowSizeStyleSmall, NSTableViewRowSizeStyleMedium or NSTableViewRowSizeStyleLarge as based on what the user has set in System Preferences. There is no direct way to know the image size for the icons. If you use NSTableCellView in a View Based NSOutlineView, then the cell will automatically be setup with the correct sizes when the rowSizeStyle is set. If this is not sufficient, then you can make the assumption for the following sizes: NSTableViewRowSizeStyleSmall = 16x16, NSTableViewRowSizeStyleMedium = 18x18, and NSTableViewRowSizeStyleLarge=32x32.

For Cell Based TableViews, a default set of attributes will be applied to the cell's stringValue creating a custom attributedStringValue based on the Human Interface Guidelines. This is done before calling -willDisplayCell, so in general, it is recommended to not change the text color or font of the cell in -willDisplayCell:. In Leopard and SnowLeopard, attributes were only applied to the group header cells. For applications linked on Lion and later, custom attributes will also be applied to all other cells (specifically, a 1-pixel drop shadow). For applications that want this feature pre-Lion, they can use -willDisplayCell to customize the -attributedStringValue as desired.

For View Based TableViews, a plain NSTextField (as setup in Xcode's Interface Builder) should be returned for the header items. Or, alternatively an NSTableCellView can be used with the -textField property properly setup to a basic NSTextField. The text should be set to an uppercase string, but no attributes need to be applied; they will automatically be applied by NSOutlineView. All other rows should use NSTableCellView, which will have proper layout done based on the -rowSizeStyle set to it. In addition, the -textField property will automatically have attributes applied to it as necessary. In general, source lists should not float the group rows, and [outline setFloatsGroupRows:NO] should be called.

To add an accessory view to an NSTableCellView that resides in a sidebar source list, you will need to subclass NSTableCellView and perform layout of the additional views in -viewWillDraw. First call [super viewWillDraw] to have the standard layout of the text and image performed.

To create an unread indicator or accessory button, use an NSButton (or NSButtonCell) with a bezelStyle set to NSInlineBezelStyle. This bezel style creates a special inline look for tables. When used inside a source list, it has appropriate color attributes applied to it to appear as an unread indicator (or colored button). It will behave as a button only if the target/action is set; otherwise, it can be used as a static unread indicator. -cellSizeForBounds: properly implements the minimum size required for an unread indicator if the cell has text. If the cell has an image, it will default to a circular size.

Prior to Lion, the source list background color was a special color that varied depending on the window key state. On Lion, it is now a gradient.

Debugging NSTableView

To help debug general issues, one can have the NSTableRowView show row numbers by running the application with “-NSTableRowViewShowRows YES” as a parameter. In addition, this also works in the "Cell Based" TableView.

Debugging View Based NSOutlineView Changes

To help debug errors in calls to insert/deleting/moving inside NSOutlineView, run the application with “-NSOutlineViewValidateChanges YES”. This performs some validation to ensure the inserts/deletes/moves match what the dataSource will return. Note that this should only be turned on for testing/debugging, and will cause a slowdown for all inserts/deletes/moves inside NSOutlineView. Each validation will happen after each call to insert/delete or move (it will NOT happen at the end of batched updates called inside of a beginUpdates/endUpdates block). Errors will be reported by throwing an exception.

NSApplication

AppKit now has the ability to report uncaught exceptions. It is controlled by a user default: NSApplicationShowExceptions (YES/NO). The default shipping value is NO. In general, it is recommend that developers set it to YES during development to catch programming errors. Individual applications can automatically turn this on by using [[NSUserDefaults standardUserDefaults] registerDefaults: ...] to register the option on. It can be set with defaults via: 'defaults write com.yourdomain.app NSApplicationShowExceptions YES'. It can also globally be turned on by writing to the global domain.

NSOpenPanel / NSSavePanel

Using the new method -beginWithCompletionHandler: in 10.6 requires you to first retain the save panel (or reference it in the completion handler block, which implicitly retains it). Otherwise, the panel will briefly show and then correctly be autoreleased. For applications linked on 10.7 and later, this problem has been fixed and applications will no longer need to explicitly retain panel.

For applications linked on 10.7 and higher, URLs vended from the NSSavePanel may now contain non-file schemes (i.e.: something other than NSURLFileScheme). This will happen if they don't have a physical backing file, such as things in the SHARED section. For compatibility, certain delegate methods (such as panel:shouldEnableURL:) will only be called with non-file URLs, and all other URLs will automatically be enabled. It is recommended that the delegate always enable non-file URLs unless some other behavior is desired.

NSSavePanel and NSOpenPanel have an updated look to match Finder. This look contains four view options (includes cover flow and group options), while the classic look has only three view options and no cover flow. Carbon based applications will always use the classic option. If you have an application which crashes in the open or save panel, you can opt it out of using the new look with a user default: NSSavePanelUseFinderKit NO. Please log bugs reporting any issues encountered.

In Auto Save applications, closing a yet-unsaved document window brings up a combined alert/save panel. Since this panel includes both a "Don't Save" button and a file browser, an ambiguity is created for the keyboard shortcut cmd-d, which can stand both for "Don't Save" and "Desktop". In order to make sure users do not unintentionally lose their unsaved documents, we have chosen to go with "Desktop" for cmd-d, and have switched to using cmd-delete for "Don't Save." This new shortcut should also work in most non Auto Save applications.


NSPopover

AppKit now has a new class for presenting popovers. The header contains lots of self documentation.

NSPopover Delegate Methods

When a popover is closed and the delegate should be consulted, the following sequence of events occurs. First, the -popoverShouldClose: method will be invoked on the delegate if implemented. If the delegate returns NO, the popover will not be closed. Otherwise, if the popover instance implements -popoverShouldClose:, that method will be invoked on the popover instance and if the method returns NO, the popover will not be closed.

Due to a bug in NSPopover, however, implementing -popoverShouldClose: on the NSPopover instance will not behave as expected. It is recommended that for now -popoverShouldClose: should not be implemented on the popover instance.

Additionally, -popoverShouldClose: is currently incorrectly invoked on the popover delegate and instance if implemented when the popover detaches to a window. You should never return NO in this case.

NSPopover Bindings

A bug in AppKit prevents the NSPopover bindings from working in the initial release of 10.7.


NSButtonCell - New Bezel Style

NSButtonCell has a new bezel style: NSInlineBezelStyle. This bezel style creates a special inline look for tables and lists, but can be used in any appropriate location. When used inside a source list table view, it will have automatic color attributes applied to it to appear as an unread indicator (or colored button). To make the button appear as a label (ie: not respond to clicks), call [buttonCell setHighlightsBy:0]. -cellSizeForBounds: properly implements the minimum size required for an unread indicator if the cell has text. If the cell has an image, it will default to a circular size.

NSWindow - Child Windows Ordering Out

For applications linked on 10.7 and later, ordering out a child window will now first remove itself from its parent window. Previously, ordering out a child window would implicitly order out the parent window too.



NSColor

NSColor now has two class methods to enable creating colors with sRGB or its gray counterpart color spaces. These create colors with colorSpaceName = NSCustomColorSpace and the appropriate color space (+[NSColorSpace sRGBColorSpace] or +[NSColorSpace genericGamma22GrayColorSpace]).

These days the sRGB color space is a better match to the default Mac display environment than the calibrated color space. For this reason in general we recommend using sRGB color space for your images and in your colors—this can lead to better fidelity and performance.

In NSColor there is a change in the treatment of individual component accessor methods such as redComponent, etc. In 10.6 and earlier, these are defined to work only on colors in the named colorspaces NSCalibratedRGB and NSDeviceRGB. (Same for component accessors in the gray and CMYK color spaces.)

In 10.7, these component accessors work on any custom colorspace color which has the appropriate underlying colorspace model. So for example this means it's legal to send -redComponent to a color created with the new sRGB creating method.

It's important to note that this does not mean these methods will start doing any conversion; as before, they will work only in cases where no color space conversion is needed.


NSColorSpace

The initialization method initWithColorSyncProfile: now accepts ColorSyncProfileRef as well as CMProfileRef as before. Whatever was passed into this initializer will also be returned when the accessor method colorSyncProfile is invoked.

If colorSyncProfile is invoked on instances not created with initWithColorSyncProfile:, then colorSyncProfile will return an instance of ColorSyncProfileRef for Lion-linked apps, and an instance of CMProfileRef for earlier apps.

Note that ColorSync APIs that take ColorSyncProfileRef also take CMProfileRefs as arguments, so the intermixing of the two types should work fine.


NSTextStorage

The text system will now use UTF-8 rather than the default C-string encoding for any documents that otherwise have no encoding tags or hints, and which look like they are valid UTF-8.



Vertical Text

Mac OS X 10.7 introduces the complete vertical text writing support through out the Cocoa Text System. There are several API additions for application developers to take advantage of this typographical enhancement.

NSVerticalGlyphFormAttributeName

This NSAttributedString attribute controls the glyph appearance based on the layout orientation value specified. When non-nil, the value must be an NSNumber containing an integer value. The value 1 indicates that the run of text is to be rendered with the vertical font variant if available. The layout and rendering engine in the Cocoa Text System substitutes the NSFontAttributeName value with its vertical font returned from -verticalFont method.
0 indicates forces horizontal font regardless of higher-level layout orientation settings.

NSFont

NSFont now can manage vertical variant instances if the underlying font typeface can handle the text layout orientation. With vertical font, the text matrix is rotated 90 degrees counter-clock wise. Also, vertical glyph substitution typographic features are enabled by default. There are two API for managing vertical font instances introduced.
- (NSFont *)verticalFont;
- (BOOL)isVertical;

Text Layout Orientation

The orientation of lines rendered by NSTextView is determined by the text layout orientation property. NSLayoutManager accesses the orientation value for each view via NSTextContainer. It is allowed to have different orientation settings for views sharing a single layout manager. A new protocol, NSTextLayoutOrientationProvider, and its value enum type, NSTextLayoutOrientation, are declared in NSLayoutManager.h. NSTextContainer and NSTextView conform to NSTextLayoutOrientationProvider protocol.
@protocol NSTextLayoutOrientationProvider
- (NSTextLayoutOrientation)layoutOrientation;
@end
In addition to -layoutOrientation method, NSTextView implements -setLayoutOrientation: and -changeLayoutOrientation: methods.
- (void)setLayoutOrientation:(NSTextLayoutOrientation)theOrientation;
- (void)changeLayoutOrientation:(id)sender;

Reading and writing text layout orientation

A new text document attribute key, NSTextLayoutSectionsAttribute, is introduced for reading and writing the text layout orientation setting for each text view. The value is an array of dictionaries. Each dictionary specifies the text layout orientation for a range of string. Two keys, NSTextLayoutSectionOrientation and NSTextLayoutSectionRange, are provided for the dictionary content.

I-Beam cursor for vertical text layout orientation

When the mouse pointer enters a text area with the vertical text layout orientation, the shape should be changed to an I-beam cursor that is 90 degrees rotated. NSCursor has a new factory method for the pointer type.
+ (NSCursor *)IBeamCursorForVerticalLayout;

NSRulerView value translation

NSRulerView has a built-in facility for translating its client's coordinate system location to the ruler value. With the introduction of the vertical text layout orientation that rotates the bounds of NSTextView, the current logic is ambiguous for determining the intended axis for representing the ruler value. For example, with a vertical text view, a vertical ruler wants to translate the x coordinate value. In order to disambiguate the client view intention, NSRulerView now has an explicit value translation delegate methods.
- (CGFloat)rulerView:(NSRulerView *)ruler locationForPoint:(NSPoint)aPoint;
- (NSPoint)rulerView:(NSRulerView *)ruler pointForLocation:(CGFloat)aLocation;

Integrated Quick Look support for NSTextView

NSTextView in Mac OS X 10.7 has built-in Quick Look support for attachments. There are three new NSTextView APIs for working with the Quick Look preview panel.
- (IBAction)toggleQuickLookPreviewPanel:(id)sender;
- (NSArray *)quickLookPreviewableItemsInRanges:(NSArray *)ranges;
- (void)updateQuickLookPreviewPanel;
In the meantime, NSTextViewDelegate has a new optional delegate method, -textView:URLForContentsOfTextAttachment:atIndex:, for managing the content URL for NSTextAttachment. This delegate method can enable both Quick Look and double-click action.
- (NSURL *)textView:(NSTextView *)view URLForContentsOfTextAttachment:(NSTextAttachment *)attachment atIndex:(NSUInteger)charIndex;

NSLayoutManager glyph rendering

NSLayoutManager in Mac OS X 10.7 deprecated the glyph rendering primitive, -showPackedGlyphs:length:glyphRange:atPoint:font:color:printingAdjustment:, and introduced the following new method taking a CGGlyph array.
- (void)showCGGlyphs:(const CGGlyph *)glyphs
positions:(const NSPoint *)positions
count:(NSUInteger)glyphCount
font:(NSFont *)font
matrix:(NSAffineTransform *)textMatrix
attributes:(NSDictionary *)attributes
inContext:(NSGraphicsContext *)graphicsContext;
-[NSLayoutManager drawGlyphsForGlyphRange:atPoint:] dynamically determines which primitive to invoke based on the instance method implementation. The new primitive method is invoked regardless of the framework linkage version unless:

- the instance has an overridden implementation of the old primitive and does not have an overridden implementation of the new primitive
- the NSLayoutManagerForcesShowPackedGlyphs preference value is true


Attributed Editing with NSTokenFieldCell

NSTokenFieldCell no longer forces -allowsEditingTextAttributes to return YES.


Marked underline color rendering with NSTextView

When rendering NSMarkedClauseSegmentAttributeName, NSTextView no longer forces black NSUnderlineColorAttributeName. Since NSLayoutManager uses NSForegroundColorAttributeName in absence of NSUnderlineColorAttributeName, the NSMarkedClauseSegmentAttributeName matches the base color.


Placeholder string in focused NSTextField

The placeholder string is now displayed even with focused NSTextField.


NSSearchField

The search menu now can be popped up with the Command-Down Arrow key combination while the field has focus.


NSSecureTextField

The caps lock and num lock indicators are now rendered with a color derived from the field's text color.




Enhanced Text System Formatting controls in inspector bar

In place of the current formatting controls in the ruler accessory view, we're introducing an inspector bar containing text formatting controls much like iWork applications. This new option is available through -[NSTextView usesInspectorBar].


NSRulerView mouse handling

NSRulerView now routes mouse events occurring in the marker area in addition to the ruler area to its clients via -rulerView:handleMouseDown:. It now sends both NSLeftMouseDown and NSRightMouseDown. It is the client view's responsibility to determine the right behavior.


NSTextTab markers in ruler view

The right mouse down events reveal a context menu for choosing text tab type in Mac OS X Lion.


NSFontCollection

We introduced a dedicated class for representing font collections, NSFontCollection, previously accessed partly through NSFontManager. NSFontCollection is a bag of NSFontDescriptor. You can publicize the font collection as a named collection and presented through UI such as the font panel & Font Book.




Notes specific to Mac OS X 10.6

NSApplication presentationOptions API

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

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

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

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

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

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

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.

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

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

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

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

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

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

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

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:

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

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

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:

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:

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

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

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

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

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

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

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

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

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

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

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:]

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]

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

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

-[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

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

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

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]

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:]

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

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

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

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

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

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

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

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

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 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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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:

-[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

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:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


NSPasteboard

Multiple Pasteboard Items

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

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

- 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

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

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

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

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

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

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

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

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

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

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

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

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



Text Checking

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

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

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

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

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.

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.

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.

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.

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.

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

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

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.

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.

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.

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

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.

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

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.

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

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

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


NSColorSpace

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

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

NSColor

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

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.


NSSearchFiedlCell

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

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


NSRulerView

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

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

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

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

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.



Notes specific to Mac OS X 10.5

New features and significant changes in AppKit





64-Bit

Leopard contains 64-bit versions of many system frameworks, enabling building and running many Cocoa apps as 64-bit. There are some API changes in Cocoa to accomodate this. Most are due to the introduction of two new types, NSInteger and NSUInteger, as a way to represent "address-sized" integers on both 32 and 64-bit. NSInteger is defined as "int" on 32-bit and "long" on 64-bit, and NSUInteger is its unsigned counterpart. Almost all Cocoa-based APIs have been upgraded to use NSInteger or NSUInteger in place of int or unsigned int. NSInteger is analogous to CoreFoundation's CFIndex type.

(Note that early in Leopard, NSInteger and NSUInteger were named NSInt and NSUInt, respectively. These old names have been removed before final release of Leopard.)

Moving forward, applications should be using these new types (and CGFloat - see below) instead of int, unsigned int, and float, since this will make an eventual move to 64-bit much easier. We recommend this even for apps that need to run on Tiger; they can accomplish this with their own, Tiger-only definitions of these types.

We have a conversion script in /Developer/Extras/64BitConversion to help convert Cocoa applications to 64-bit. Information about this script and the Cocoa 64-bit effort in general can be found in the 64-Bit Transition Guide for Cocoa.

In general it should be possible to use the same source base for both the 32 and 64-bit versions of an application or framework. Running this script on your source base to convert your sources to 64-bit should still enable them to build and run correctly under 32-bit. If needed, you can do:
#if __LP64__
...
#endif
as a way to do 64-bit specific code.


In APIs where the term "int" appeared as a part of the method name (for instance, "intValue"), the term "integer" is used to represent this new NSInteger type, while "int" continues to refer to the native int type (which is 32-bit under both 32 and 64). Thus methods like intValue, numberWithInt:, scanInt:, etc continue to take or return ints, while methods such as integerForKey: in NSUserDefaults have been changed to take NSInteger. We are adding a number of counterpart methods in Foundation and AppKit that take or return NSInteger or NSUInteger arguments.

The new methods in Foundation are:

NSCoder:
 - (void)encodeInteger:(NSInteger)intv forKey:(NSString *)key;
- (NSInteger)decodeIntegerForKey:(NSString *)key;
NSString:
 - (NSInteger)integerValue;
NSScanner:
 - (BOOL)scanInteger:(NSInteger *)ptr;
NSNumber:
 - (NSInteger)integerValue;
- (NSUInteger)unsignedIntegerValue;
- (id)initWithInteger:(NSInteger)value;
- (id)initWithUnsignedInteger:(NSUInteger)value;
+ (NSNumber *)numberWithInteger:(NSInteger)value;
+ (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value;
For the AppKit, this means the following new methods in both NSCell and NSControl:
- (NSInteger)integerValue;
- (void)setIntegerValue:(NSInteger)val;
- (void)takeIntegerValueFrom:(id)sender;
We also have the following new constants in NSObjCRuntime.h:
 #define NSIntegerMax   LONG_MAX
#define NSIntegerMin LONG_MIN
#define NSUIntegerMax ULONG_MAX

Note that by design, keyed archiving's handling of integral types is not strict. An integer quantity written with any of encodeInteger:forKey:, encodeInt32:forKey:, or encodeInt64:forKey: can be read back using any of the integer decode methods. If the value is too large to read using the specified decode method, an exception is raised.

For most integral values, we recommend the use of encodeInteger:forKey: and decodeIntegerForKey:. For values whose ranges are larger than what 32-bit signed integers can hold, the Int64: variants continue to be the more appropriate choice, even on 32-bit.

There are additional archiving and other considerations in the presence of 64-bit changes in our APIs. The 64-bit Transition Guide referred to above has more information on this topic and more.


CGFloat

Another major change in Cocoa APIs is the introduction of the CGFloat type in Quartz. This replaces the use of float, and is defined as double for 64-bit. Note that this is not a change dictated by the 64-bit move; however, we are taking advantage of the move to introduce this new type. The purpose of CGFloat is to provide higher precision and range in graphical values, for 64-bit applications. This type replaces the use of all graphical float types in Cocoa APIs, including those in Foundation's NSGeometry.h.

Another change in NSGeometry.h is the redeclaration of NSRect, NSPoint, and NSSize using the Quartz counterparts, CGRect, CGPoint, and CGSize. Unfortunately, due to binary compatibility considerations, this change is done for 64-bit only. Note that the Objective C type signatures of these types thus differs on 64-bit from that on 32-bits.


Enum name removal

As a part of 64-bit clean-up, we added explicitly sized types where we were previously using enums. For instance, we went from:
typedef enum NSAlertStyle {
NSWarningAlertStyle = 0,
NSInformationalAlertStyle = 1,
NSCriticalAlertStyle = 2
} NSAlertStyle;
to
enum {
NSWarningAlertStyle = 0,
NSInformationalAlertStyle = 1,
NSCriticalAlertStyle = 2
};
typedef NSUInteger NSAlertStyle;
The latter makes sure that NSAlertStyle remains a fixed size and signedness no matter how the enum contents change.

In doing this, we removed the enum names from the enum declarations, so any attempt to use "enum NSAlertStyle" will now fail. Please switch to using the typedef instead, which is fixed size.

NSOpenGL and 64-Bit

The AppKit API declarations in NSOpenGL.h have been changed to use standard OpenGL types (GLint, GLsizei, GLenum, and GLbitfield) in place of explicit C "int" and "long" types, to help facilitate the transition to 64-bit. The effective sizes and signedness of the parameters and return values remain the same as before for 32-bit development.

APIs removed in 64-Bit AppKit

A number of classes have been removed in 64-bit version of AppKit:

- NSMenuView - You can use NSView customizations on NSMenuItem
- NSMovieView - Use QTKit
- NSMovie - Available with very limited functionality (see here); use QTKit
- NSQuickDrawView - QuickDraw is not supported in 64-bit
- NSSimpleHorizontalTypesetter - Deprecated for a while now, use the new NSTypesetter facilities

In addition, a number of previously deprecated individual APIs have also been removed from the 64-bit AppKit, including the old Display PostScript related symbols exported solely for binary compatibility under 32-bit.


Objective-C 2.0

Leopard includes Objective-C 2.0, which brings a number of new features to the language and runtime: Fast enumeration, garbage collection, class extensions, properties, method and class attributes, and optional methods on protocols.

There are a number of additional runtime features available in 64-bit only: Stricter access control on private instance variables and classes, "non-fragile" instance variables, and C++ compatible, "zero-cost" exceptions (which are very cheap to set up, but expensive to throw).

It is important to note that all of these features are Leopard-only. Please refer to the Objective-C 2.0 documentation for full details on these features.

Note that many Objective-C APIs in Leopard have not yet adopted these features. But in future releases, you are likely to see:

- @property used to declare properties
- Delegate declarations switched from informal protocols (categories on NSObject) to formal protocols, with optional methods
- Increased restricted visibility of private symbols in the runtime

The last point is especially important, since it would prevent applications using these symbols from launching in future releases. As always: Please do not access undeclared APIs in your applications. This includes undeclared classes, methods, and instance variables. If you have a strong need for a private API and have no workaround, please let us know.


Interface Builder 3.0

Leopard developer tools includes a new version of Interface Builder (IB). IB 3.0 has a redesigned interface, a much improved integration with Xcode, and ability to access many more AppKit features in your nib files than before.

IB 3.0 supports three file formats. The 2.x file format is same file format that's been in use in Interface Builder previously. It can be edited by IB 2.0, and is deployable on earlier versions of Mac OS X. The 2.x file format does not support some new features of IB, such as the ability to edit custom cell subclasses and toolbars. The 3.x file format supports all the new features, is also deployable on earlier versions of Mac OS X, but can only be edited with IB 3.0. IB 3.0 also supports a textual, human-readable format called the "xib" format. This format is equivalent to the 3.x format, but it's more SCM-friendly. It is compiled down to a 3.x file at build time.

For editing and building your project on Leopard only, we recommend the xib format, since it provides the best development time experience. If you need to build your project on Tiger, but edit your nibs on Leopard only, then you can use the 3.x format. Finally, if you wish to be able to continue to edit your nib files on Tiger, you can stick to the 2.x format. In all these cases, the files can be deployed on Tiger, but some features supported by IB 3.0 may not work on the earlier systems. IB has facilities to warn you in those cases.


Core Animation Layer Tree Rendering

Leopard AppKit provides the means to render a Core Animation layer tree inside the bounds of any given NSView. Clients need only provide the root CALayer of the layer tree to be displayed, then enable layer tree rendering for the same view:
    [view setLayer:rootLayer];
    [view setWantsLayer:YES];
AppKit responds by setting up a Core Animation renderer that animates and composites the layer tree on a background thread.

The Core Animation renderer continues its asynchronous operation until layer tree rendering is disabled for the view (via a setWantsLayer: message with a parameter of NO), or the view is hidden or removed from the window. Un-hiding a view, or adding a view that has wantsLayer enabled to a window, resumes layer tree rendering.

To conserve system resources, AppKit also suspends layer tree rendering for the views in a given window when the window is ordered out, and for all the views in a process when the user's login session is switched out via the "Fast User Switching" feature. In such cases, layer tree rendering automatically resumes when the window is ordered back in, or when the user's login session is switched back in, as appropriate.

See the documentation for the QuartzCore framework's new Core Animation API for more information about layer tree creation, capabilities, and use.

New View Animation Facilities, and Layer-Backed View Drawing

In addition to supporting rendering of user-defined Core Animation layer trees, Leopard AppKit adopts API paradigms similar to Core Animation's to allow clients to request animation of view and window properties, and also adds a new "layer-backed" mode for rendering and animation of view trees. Use of layer-backed mode is not required in order to use AppKit's new CAAnimation-based API, but does enable the use of additional new visual treatments for views (per-view overall alpha, shadows, and the ability to apply Core Image filters to rendered content), and accelerates animation of nonresizing views for the price of caching their rendered content into per-view CALayers.

In conventional view rendering, a window's view tree is drawn back-to-front into the window's backing store. The drawn view content is thus pre-composited into a single backing store, in such a way that updating any given part of the window requires re-drawing the affected parts of all the views that contribute to the result. In the new "layer-backed" view drawing mode that is now supported in Leopard, each of the views in a layer-backed view subtree has its content drawn to its own layer in an AppKit-created-and-managed CALayer tree. This carries an additional memory cost, of order (4 * pixels wide * pixels high) bytes per view, that should be weighed when considering whether and where to employ layer-backed mode in an application's user interface, but in return it enables already-rendered view content to be moved around more efficiently during animations, since the content only has to be re-compositied instead of being re-rendered from scratch.

Most of the standard views and controls that AppKit and Mac OS X's other Cocoa frameworks provide are able to function in layer-backed mode in Leopard, with the exception of certain specialized views such as WebKit WebViews and Quartz Composer QCViews, whose use in layer-backed mode is not presently supported.

Layer Size Limits and Tiled Layers

One inherent limitation of rendering view content into a Core Animation layer is that the size of ordinary CALayers is constrained by the maximum OpenGL texture size supported by the host system's graphics hardware. On most current graphics hardware the effective limit is 2046x2046 pixels, beyond which size layer creation will fail. Care should therefore be taken to insure that layer-backed views do not exceed this size limit.

To get around this limitation for potentially larger document views, AppKit employs CATiledLayers to serve as the backing layers for the document views of NSScrollViews. This specialized layer type caches its content in a grid of "tiles" (of default size 256x256 pixels) that are drawn as they become visible, and can be garbage-collected when they go out of view. From the user's perspective, the tiles are added asynchronously as they are revealed during scrolling. The visual appearance of the tile addition can be minimized by enabling the "drawsBackground" property for the enclosing NSScrollView (or, equivalently, its NSClipView), and choosing a background color that most closely matches the document view content being drawn.

Note that when using layer-backed mode for an NSScrollView's document view, it's necessary for the enclosing NSScrollView, or at least its NSClipView ("content view"), to also be layer-backed in order for scrolling to function correctly.

Using Layer-Backed Views

A quick-start guide for beginning to experiment with this functionality:

1. Choose a view that will serve as the root view for Core Animation-based view rendering, and switch on Core Animation-based rendering for that view (and implicitly its descendants) by doing [theRootView setWantsLayer:YES];

2. Properties of views and windows for which auto-animation is supported can be animated by messaging through the target object's (view's or window's) "animator" proxy:
    [[someDescendantOfTheRootView animator] setFrame:newFrame];
To specify a duration in place of the global default of 0.25 seconds, enclose such messages in an NSAnimationContext that specifies the duration for animation:
    [NSAnimationContext beginGrouping];
    [[NSAnimationContext currentContext] setDuration:0.25];
    [[someDescendantOfTheRootView animator] setFrame:newFrame];
    [NSAnimationContext endGrouping];
Basic default animation parameters are provided for the following NSView and NSWindow properties, such that they will animate automatically when assigned a new target value via the view or window's animator:

for NSView: alphaValue, frame, frameOrigin, frameSize, frameRotation, frameCenterRotation, bounds, boundsOrigin, boundsSize, backgroundFilters, contentFilters, compositingFilter, shadow

for NSWindow: alphaValue, frame

Some further notes regarding the new animation and visual property additions to NSView follow, in the "NSAnimationContext", "new NSView properties", and "NSAnimation additions" sections.

NSAnimationContext

NSAnimationContext is a new class in Leopard. NSAnimationContexts are analogous to Core Animation's CATransactions, and are also somewhat similar in overall concept to NSGraphicsContexts. Each thread maintains its own stack of nestable NSAnimationContext instances, with each new instance initialized as a copy of the instance below it (so, inheriting its current properties). Currently, an NSAnimationContext exists for the sole purpose of holding the default duration to be used for "animator"-proxy-initiated animations.

Each thread starts with a current NSAnimationContext whose default duration is 0.25 seconds (the same default value used by Core Animation), meaning that value-set operations for animatable object properties that go through "animator" proxies will animate with that duration by default. To animate with a different duration, a section of code would begin a new NSAnimationContext with the desired duration, perform the desired value-set operations through "animator" proxy or proxies, then close the context when done:
    [NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:1.0]; // Animate enclosed operations with a duration of 1 sec
[[aView animator] setFrame:newFrame];
[NSAnimationContext endGrouping];
NSAnimationContexts can be nested, allowing a given block of code to initiate animations using its own specified duration without affecting animations initiated by surrounding code.
    [NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:1.0]; // Animate enclosed operations with a duration of 1 sec
[[aView animator] setFrame:newFrame];
...
[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:0.5]; // Animate alpha fades with half-second duration
[[aView animator] setAlphaValue:0.75];
[[bView animator] setAlphaValue:0.75];
[NSAnimationContext endGrouping];
...
[[bView animator] setFrame:secondFrame]; // Will animate with a duration of 1 sec
[NSAnimationContext endGrouping];
Since an "animator" proxy can be handed off to code that expects an ordinary object of the kind the proxy targets (presently, an NSView or NSWindow), it might in rare circumstances be necessary to suppress animation for code that does not explicitly go through "animator" proxy objects. This can be accomplished using an animation context with a duration of zero:
    [NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:0.0]; // Makes value-set operations take effect immediately
[aViewOrMaybeAnAnimator setFrame:newFrame];
[NSAnimationContext endGrouping];

New NSView properties

Leopard AppKit adds some new properties to NSViews, which are described below with their corresponding accessor methods.
- (void)setWantsLayer:(BOOL)flag;
- (BOOL)wantsLayer;
The "wantsLayer" property determines whether a view and its descendants should be composited and animated using a Core Animation layer tree, enabling the use of advanced animation and compositing effects. Defaults to NO. Setting this property to YES for the rootmost view for which Core Animation-based compositing is desired is all that's needed to activate Core Animation-based view buffering, compositing, and animation for a given view subtree. The view subtree is then said to be "layer-backed", since each view is given a corresponding Core Animation layer that serves as its backing store.
- (CALayer *)layer;
The -layer method returns the view's corresponding AppKit-created-and-managed CALayer, if the view is layer-backed. Callers may use the returned pointer to message the layer directly, as a means of accessing features that aren't re-exported as NSView properties. May return nil for a view that's currently marked as layer-hosted, if AppKit hasn't yet displayed the view for the first time and thus created the view's layer. For most ordinary usage of animating views' frames and content and applying effects, awareness of and direct access to views' underlying layers is unlikely to be needed, as AppKit will be able to manage them automatically.
- (void)setLayer:(CALayer *)newLayer;
The -setLayer: method sets a given CALayer to be a view's backing layer. This causes the view to dissociate from its previously assigned layer (if any), removing that layer from its surrounding layer tree and releasing the view's reference to the layer. The new layer takes on the old layer's position in the layer tree (or is simply added to the layer tree in the appropriate place, if it isn't replacing an existing layer). A view retains its layer, but AppKit maintains only a weak reference from the layer back to the view. This method manages both associations.

-setLayer: is published to allow for the usage where a developer has an arbitrary layer tree that's not tied to a view subtree and isn't automatically managed by AppKit, and wants to render that in a view (see "Core Animation Layer Tree Rendering").
- (void)setAlphaValue:(CGFloat)viewAlpha;
- (CGFloat)alphaValue;
Sets the overall opacity value with which the view and its descendants are composited into their superview (analogous to a window's alphaValue). Defaults to 1.0. This setting may be varied independently of the class' return value for -isOpaque, and the implementation of the latter needn't take the view's alphaValue into account, since AppKit consults both values when necessary. A view's alphaValue will affect both Core Animation-based and conventional view compositing.
- (NSShadow *)shadow;
- (void)setShadow:(NSShadow *)shadow;
Sets an optional shadow to be drawn behind the view subtree. Defaults to nil. This setting only has an effect for Core Animation-based view compositing. Note that, although Core Animation's shadow model uses the same parameters as a Quartz shadow, the rendered results may differ from those achieved using Quartz shadow rendering. NSShadow is used here merely as an appropriate Cocoa encapsulation for the identical set of shadow parameters.


The following three pairs of accessor methods can be used to apply arbitrary Core Image filter effects for views that are backed by CALayers. As specified by Core Animation, the conceptual model used to apply filter operations and combine their results is:
   maskop(mask, compositeop(layerop(layer), backgroundop(background)), background)
- (CIFilter *)compositingFilter;
- (void)setCompositingFilter:(CIFilter *)filter;
Sets a CIFilter that will be used to composite the view subtree over its (possibly filtered) background. Defaults to nil, which implies that source-over compositing should be used. This setting only has an effect for Core Animation-based view compositing.
- (NSArray *)contentFilters;
- (void)setContentFilters:(NSArray *)filters;
Allows the view's content to be filtered through an optional chain of CIFilters before being composited into the render destination. The supplied array of filters needn't be connected to one another, as they will be connected in series automatically by Core Animation. Defaults to nil. This setting only has an effect for Core Animation-based view compositing.
- (NSArray *)backgroundFilters;
- (void)setBackgroundFilters:(NSArray *)filters;
Allows the background behind the view's subtree to be filtered through an optional chain of CIFilters before the view subtree is composited into it. The supplied array of filters needn't be connected to one another, as they will be connected in series automatically by Core Animation. Defaults to nil. This setting only has an effect for Core Animation-based view compositing.

Layer-Backed Views and Out-of-Band Drawing

For the ordinary case of views drawn into a shared window backing store, it has historically been possible to draw into the window area that a view occupies at will, by locking focus on the view, drawing, and unlocking focus:
    [view lockFocus];
/* Perform some drawing. */
[view unlockFocus];
This was sometimes used to replace some animated content in response to a timer callback, for example.

Due to the inherently different buffering semantics for layer tree based rendering, this technique cannot be used by layer-backed views. Instead, you should perform all needed drawing in -drawRect:, and use -setNeedsDisplay: and/or -setNeedsDisplayInRect: to prompt updates as needed. This is generally a preferred technique anyway, since it avoids potential inconsistencies with -drawRect:-based drawing, allows other views to contribute potentially necessary content to the affected window area, and enables AppKit to coalesce updates for greater efficiency.

Avoiding Synchronization Issues with Layer-Backed View Animations

When a view is resized, the content that it draws can respond in potentially arbitrary ways.  For this reason, AppKit's "animator" proxy based animation API asks resizing views to redraw their content at each step along the way, to insure correct results.

When used with layer-backed views, this can lead to synchronization problems where a single view can appear to "jitter" when its frameOrigin and frameSize are simultaneously animated, or where gaps between adjacent animating views fluctuate, because each view's frameOrigin move is being animated on a background thread by Core Animation.  Such synchronization problems can be remedied by insuring that the view frame animations are initiated using a -setFrame: message to each view's animator, rather than going through -setFrameOrigin: and/or -setFrameSize: separately.  This cues AppKit to animate both the frameOrigin and frameSize changes itself, so that the results will stay in sync throughout the animation.

Note that AppKit-driven animations are timer-based, and thus require normal periodic runloop servicing to occur in order for them to advance.  For best results, try to avoid having lengthy operations block the runloop while AppKit-driven animations are in flight.

Layer-backed NSImageView optimization

For complex views, animations that cause the frame size to change often result in sub-optimal animation performance. When the view's size changes, it must redrawn for each frame of the animation, which often lowers framerates. NSImageView is a good example of this, since rendering images can be expensive. NSImageView has been optimized in certain cases for resizing animations. The following is a set of conditions that must be met in order for the optimization to take effect:

• The image view must be uneditable and have a frame style of NSImageFrameNone.
• The image view must contain AppKit's standard NSImageCell and the view's drawRect: method must not be overridden.
• The view must be layer-backed and must be using the layer that AppKit creates for it (meaning you may not provide your own layer with -setLayer:).
• The "best" image rep (according to -bestRepresentationForDevice:) for the view's image must be an NSBitmapImageRep, NSCachedImageRep, NSPICTImageRep, or NSCGImageRep.
• The view's imageScaling must be NSImageScaleProportionallyUpOrDown with centered imageAlignment or NSImageScaleAxesIndependently or NSNSImageScaleNone with any imageAlignment. Note that the default imageScaling is NSImageScaleProportionallyDown which does not allow the optimization to take effect.

Shifting "needsDisplay" Rectangles in a View

The following method enables shifting of the receiving view's dirty rects in a single operation. The effect of this method is to get all of the receiving view's dirty rectangles, clear all dirty rectangles in the intresection of the specified clipRect and the view's bounds, shift the retrieved rectangles by the given "delta" offsets, clip the result to the intersection of clipRect and the view's bounds, and add the resultant rectangles back to the view.
- (void)translateRectsNeedingDisplayInRect:(NSRect)clipRect by:(NSSize)delta;
This method should rarely be needed, but may be useful to clients that implement their own copy-on-scroll logic.

Pixel Alignment and Transforming View Coordinates To and From "Base" Space

In Leopard, NSView provides a new set of methods that should be used when performing pixel-alignment of view content. They provide the means to transform geometry to and from a "base" coordinate space that is pixel-aligned with the backing store into which the view is being drawn:
- (NSRect)convertRectToBase:(NSRect)aRect;
- (NSPoint)convertPointToBase:(NSPoint)aPoint;
- (NSSize)convertSizeToBase:(NSSize)aSize;
- (NSRect)convertRectFromBase:(NSRect)aRect;
- (NSPoint)convertPointFromBase:(NSPoint)aPoint;
- (NSSize)convertSizeFromBase:(NSSize)aSize;
For conventional view rendering, in which a view hierarchy is drawn flattened into a window backing store, this "base" space is the same as the coordinate system of the window, and the results of using these new methods are the same as converting geometry to and from view "nil" using the existing -covert[Rect/Point/Size]:[to/from]View: methods.

Views that are rendered into backing layers in a Core Animation layer tree, however, have their own individual backing stores, which may be aligned such that window space is not necessarily the appropriate coordinate system in which to perform pixel alignment calculations.

These new coordinate transform methods provide a way to abstract view content drawing code from the details of particular backing store configurations, and always achieve correct pixel alignment without having to special-case for layer-backed vs. conventional view rendering mode. Regardless of the underlying details of how view content is being buffered, converting to base space puts one in the native device coordinate system, in which integralizing coordinates produces pixel alignment of geometry.

When using layer-backed views at a user interface scale factor other than 1.0, note that the dimensions of a view and the dimensions of its corresponding backing layer will vary according to the scale factor, since CALayer bounds are always expressed in pixels, while NSView dimensions remain expressed in points. Most clients of layer-backed views will not have a need to perform operations directly in layer space, but for those that do it's important to use the preceding methods to convert geometric quantities between view space and layer ("base") space when appropriate.

Responding to View Hiding/Unhiding

Hiding or un-hiding a given view using the -setHidden: API affects the effective visibility of all of its descendant views. Leopard adds two new NSView methods that clients can override, if desired, to have their custom view classes respond to becoming effectively hidden or unhidden vis-à-vis the -setHidden: API:
- (void)viewDidHide;
- (void)viewDidUnhide;
A view will receive a "viewDidHide" message when its "isHiddenOrHasHiddenAncestor" state goes from NO to YES. This can happen when the view or an ancestor is marked as hidden, or when the view or an ancestor is spliced into a new view hierarchy.)

A view will receive a "viewDidUnhide" message when its "isHiddenOrHasHiddenAncestor" state goes from YES to NO. (This can happen when the view or an ancestor is marked as not hidden, or when the view or an ancestor is removed from its containing view hierarchy.)

Performing Just-Before-Drawing View Activity

NSView has a new "-viewWillDraw" API method in 10.5 that can be overridden to perform any last-minute activity that might be desired at the outset of a view hierarchy "-display..." operation.
- (void)viewWillDraw;
Most often, the activity to be performed at this time consists of some combination of view layout (assigning new frame sizes and/or positions to views) and marking additional view areas as needing display (typically as the result of performing layout of non-view content, such as text glyphs, graphics, or web content). The desired effect is to perform such computations on demand, deferred until their results are about to actually be needed, allowing for the same kind of update coalescing performance benefits that we get with the deferred display mechanism itself, rather than forcing content layout to be performed immediately when the content is established or deferred until a subsequent drawing pass.

At the outset of recursive display of part or all of a view hierarchy, which is always initiated by one of NSView's eight public "-display..." methods, AppKit recurses down the view hierarchy, sending a -viewWillDraw message to each of the views that may be involved in the display operation.

NSView's default implementation of this method is itself the mechanism for the recursion, and allows overriders the flexibility to head-recurse or tail-recurse as best suits the needs of the operations they have to perform. Conceptually, NSView's implementation looks like:
@implementation NSView
- (void)viewWillDraw {
    if (any descendant of self overrides "-viewWillDraw") {
        for (each subview that intersects the window area being drawn in back-to-front order) {
            [subview viewWillDraw];
        }
    }
}
@end
So an override of this method could do:
- (void)viewWillDraw {
    /* Perform some operations before recursing for descendants. */
    /* Now recurse to handle all our descendants. Overrides must call up to super like this. */
    [super viewWillDraw];
    /* Perform some operations that might depend on descendants already having had a chance to update. */
}
During the -viewWillDraw recursion, sending of -setNeedsDisplay: and -setNeedsDisplayInRect: messages to views in the hierarchy that's about to be drawn is valid and supported, and will affect AppKit's assessment of the total area to be rendered in that drawing pass.

If desired, an implementation of -viewWillDraw can use NSView's existing -getRectsBeingDrawn:count: method to obtain a list of rectangles that bound the affected area, enabling it to restrict its efforts to that area.

Setting a View's Subviews

NSView has a new -setSubviews: API method in 10.5 that can be used to reorder a view's subviews, remove existing subviews, and/or add new subviews all via a single API entry point:
- (void)setSubviews:(NSArray *)newSubviews;
With this single method, one can:
- reorder the receiver's existing subviews
- add or remove subviews from the receiver
- potentially replace all of the receiver's previous subviews with a whole new set of views
- potentially remove all of the receiver's previous subviews, leaving it with none (think "[aView setSubviews:[NSArray array]]")

The views in the "newSubviews" array can by any combination of existing subviews of the receiver, subviews of other views, or views that currently have no superview. If "newSubviews" is nil, or contains any duplicate entries, -setSubviews: throws an invalid argument exception. (Prior to the WWDC 2007 Leopard seed, -setSubviews: would also raise an exception if any of the new subviews was already a subview of some view. This is now allowed, and simply results in the views being removed from their previous superviews before being added as subviews of the receiver.)

Given a valid "newSubviews" parameter, -setSubviews: performs whatever sorting of the subviews array, subview addition, and subview removal activity is necessary to leave the receiver with the requested new array of subviews. Thus, any member of "newSubviews" that isn't already a subview of the receiver is added. Any member of the view's existing "subviews" array that isn't in "newSubviews" is removed. And any views that are in both "subviews" and "newSubviews" is simply moved in the subviews array as needed, without being removed and re-added. The -setSubviews: method also marks affected view/window areas as needing display to reflect the new z-ordering.

Views, Focus Rings, and Drawing Performance

To help guarantee correct redraw of focus rings, AppKit may automatically draw additional parts of a window beyond those that application code marked as needing display. It may do this for the first responder view in the application's key window, if that first responder view's focusRingType property is set to a value other than NSFocusRingTypeNone. Any view that can become first responder, but doesn't draw a focus ring, should have its focusRingType set to NSFocusRingTypeNone to avoid unnecessary additional redraw.

NSAnimatablePropertyContainer protocol

NSAnimatablePropertyContainer is a new protocol in Leopard, currently adopted by NSView and NSWindow. The methods in NSAnimatablePropertyContainer are as follows:
- (id)animator;
The -animator method returns a proxy object for the receiver that can be used to initiate implied animation of property changes. An object's "animator" should be treated as if it was the object itself, and may be passed to any code that accepts the object as a parameter. Sending of KVC-compliant "set" messages to the proxy will trigger animation for automatically animated properties of its target object, if the active NSAnimationContext in the current thread has a duration value greater than zero, and an animation to use for the property key is found by the -animationForKey: search mechanism defined below. An object's automatically animated properties are those for which [theObject animationForKey:] finds and returns an CAAnimation instead of nil, often because [[theObject class] defaultAnimationForKey:] specifies a default animation for the key.

It's perfectly valid to set a new value for a property for which an animation is currently in progress; this simply sets a new target value for that property, with animation to the new target proceeding from whatever current value the property has reached. An in-flight property animation can be stopped by setting a new value for the property with 0.0 as the surrounding NSAnimationContext's duration value.

For the common specific case of animating views:
Initiating animation via an "animator" proxy object works under both Core Animation-based and conventional view compositing. The primary difference under Core Animation-based compositing is that for intrinsic geometric properties such as the view's "frame," all animation is handled at the Core Animation level, meaning that the view's property will be immediately set to the desired target value, and the view won't see the successive intermediate values. The animation effect in such cases is purely visual and exists only in Core Animation's "render tree" backend. In contrast, under conventional (non-layer-backed) view compositing, view property animations are executed at the AppKit level, and during the course of those animations views will receive value-set operations for successive intermediate values. This is also true for animation of all developer-defined properties, under both layer-backed and conventional view compositing and animation.
- (NSDictionary *)animations;
- (void)setAnimations:(NSDictionary *)dict;
An animatable property container's optional "animations" dictionary maps NSString keys to CAAnimation values. When an occurrence matching the key fires for the view, -animationForKey: first looks in this dictionary for an animation to execute in response.
- (id)animationForKey:(NSString *)key;
When the occurrence specified by "key" fires for an object, -animationForKey: is consulted to find the animation, if any, that should be performed in response. Like its Core Animation counterpart, -[CALayer actionForKeyPath:], this method is a funnel point that defines the standard order in which the search for an animation proceeds, and is not one that clients would typically need to override. This method first checks the receiver's "animations" dictionary, then falls back to +defaultAnimationForKey: for the receiver's class.
+ (id)defaultAnimationForKey:(NSString *)key;
As described above, -animationForKey: next consults the class method +defaultAnimationForKey: when its search of an instance's "animations" dictionary doesn't turn up an animation to use for a given property change.

NSView's +defaultAnimationForKey: method returns a default animation that should be performed when the occurrence specified by "key" fires for a view, where "key" typically names a property whose value is being changed. For each of NSView's own animatable properties, NSView's implementation returns a suitable default CAAnimation to be used. For all other keys this method returns nil.

A developer implementing a custom view subclass can enable automatic animation of the subclass' added properties by overriding this method, and having it return the desired default CAAnimation to use for each of the property keys of interest. The override should defer to super for any keys it doesn't specifically handle, facilitating inheritance of default animation specifications.
@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

NSCollectionView

A new view class has been added to facilitate interesting animations: NSCollectionView. You can set or bind a collection view's content to an array of objects. For each object, the collection view will create an NSCollectionViewItem, which in turn manages a view that is used to display the values of its "represented object." All views automatically create a layout to fit all items into its content and animates them if the content changes (for example, if the content is reordered, it will slide the items into the new positions).

Usually collection view items are created from a "prototype" which is set as the "itemPrototype" outlet in Interface Builder. For the view of the collection view item, you can use standard controls/views to form a "compound" view. For example, you can group an NSImageView and an NSTextField in an NSBox to form a unit that displays images and names for it. To set the view used by a collection view item, you typically use the "view" outlet.

To populate a collection view item's view with values from the represented object, you will typically create bindings from the view (or any of the subviews) to the "representedObject" of the collection view item (example: you could bind the value binding of text field to the key "representedObject.name" of the collection view item). Alternatively, you could subclass NSCollectionViewItem and make it the data source or delegate of one of the views.

Note that in early Leopard seeds (including WWDC 2006) NSCollectionView was known as NSGridView, and NSCollectionViewItem was NSLayoutItem. As foreshadowed in the release notes, these classes have changed; however, the changes are limited strictly to the two class and several method name changes:

- layoutView in NSLayoutItem has become collectionView
- minGridSize, maxGridSize, and corresponding setter methods have become minItemSize, maxItemSize, setMinItemSize:, and setMaxItemSize:
- newLayoutItemForRepresentedObject: is now newItemForRepresentedObject:
- layoutItemPrototype and setLayoutItemPrototype: are now itemPrototype and setItemPrototype:

The old names have been removed in the final version of Leopard.


Resolution Independence

On Leopard, resolution independence (aka "HiDPI") is a developer feature. You can use QuartzDebug in /Developer/Applications/Performance Tools to set the user space scale factor to 1.25, 1.5, 2.0, or 3.0, then launch your application. The user interface of your application will be scaled by the user space scale factor.

Most standard controls are now drawn in high resolution, which allows them to appear crisp when running with user space scaling enabled.

In addition a number of standard images are now available in high-resolution, enabling graphics to appear crisp when scaled. Names of these images are declared in NSImage.h. Note that it's important to use these images only for the purpose indicated by the name, since the actual graphic may change in future releases. See the NSImage section for more info.

There are some known issues with the non-integral scale factors of 1.25 and 1.5.

- Most drawing should occur on integral pixel boundaries, but views are not automatically constrained to fall on pixel boundaries
- Image tiling also looks most correct if the tiled image is integral-pixel sized and adjusted as needed to avoid pixel cracks
- Tracking rects on non-integral boundaries may generate a mouseEntered: event while the mouse is still slightly outside the fractional bounds, or a mouseExited: while the mouse is still slightly inside the fractional bounds.
- Some controls on non-pixel boundaries may have jagged edges if the end caps do not vertically or horizontally align with the fill
- Text may jitter when scrolling if the scrollView is on a non-pixel boundary

You can use -[NSView centerScanRect:] to position a view or a rect within a view on pixel boundaries.  On Tiger, this method used NSIntegralRect, which expanded the given rectangle outward as needed to land on integral pixel values.  On Leopard, this method is size preserving, which results in better layout behavior when applied to adjacent rectangles.  This change applies only to applications linked on Leopard or later for compatibility reasons. Alternatively, you can convert to window coordinates using -[NSView convertRectToBase:], round the result to integral values with rounding rules that suit your needs, then convert back to view coordinates using -[NSView convertRectFromBase:].

Because the scaling from points to pixels is non-integral when the user space scale factor is non-integral, you need to be sure not to use floor, ceil, or round on coordinates expressed in points. This rounding would be likely to result in non-integral pixel values, which would lead to the problems listed above.

NSOpenGL and resolution independence

Applications and frameworks that are striving to become resolution-independent can encounter problems with OpenGL usage, due to the fact that many OpenGL API functions, such as glViewport(), expect their parameters in pixel units. Code that is accustomed to running under a user interface scale factor of 1.0 may contain latent errors where view dimensions were incorrectly treated as if they were in pixel units. For scale factors other than 1.0, the distinction between view space units and device (pixel) units becomes much more important to properly observe.

A common usage pattern in Cocoa-based OpenGL applications, for example, has been to pass a view's bounds dimensions directly to glViewport(), which expects to receive its parameters in pixel units:
- (void)reshape {
NSSize bounds = [self bounds];
    // This is technically INCORRECT, because bounds is not expressed in pixel units.
glViewport(0, 0, bounds.size.width, bounds.size.height);
}
To help ease the transition to resolution independence for applications that use this common code pattern, Leopard AppKit automatically configures the bounds of any view that has an associated NSOpenGLContext (thus, NSOpenGLViews, as well as ordinary NSViews that are drawn into using an NSOpenGLContext) so that the bounds are expressed in pixel units, according to the current user interface scale factor. So for example, if an application has an NSOpenGLView whose frame size is 100x100 points, and that application is run at a user interface scale factor of 1.25, the NSOpenGLView's frame will remain 100x100 points, but its bounds will be reported as 125x125. That enables commonly used code constructs such as the above -reshape method to function correctly without code changes.

While this automatic workaround may suffice to provide compatibility for many applications, the ideal solution is for OpenGL client code to perform correct unit conversions where needed. For example, the above -reshape method would be more correctly written as:
- (void)reshape {
// Convert up to window space, which is in pixel units.
NSSize boundsInPixelUnits = [self convertRect:[self bounds] toView:nil];
    // Now the result is glViewport()-compatible.
glViewport(0, 0, boundsInPixelUnits.size.width, boundsInPixelUnits.size.height);
}
Code that targets Mac OS 10.5 and later can use the -convertRectToBase: method instead of converting to view nil, which has the advantage of correctly producing a result in pixel units regardless of whether the view is layer-backed. (If the view is layer-backed, -convertRectToBase: converts to the coordinate space of the layer's backing store, instead of to the window's coordinate space.)

Text rendering and resolution independence

When rendering with non-integral scale factor, we recommend you use the antialiased text rendering mode. Since the glyph origin might not be pixel-aligned at layout time, rendering non-antialiased text doesn't produce optimal quality.


NSRuleEditor

NSRuleEditor is a new AppKit control introduced in Leopard. NSRuleEditor allows the user to configure "rules," similar to the rules in Mail or in the Finder search window, by selecting from popups, manipulating custom views, and adding, deleting, or rearranging rows.

NSRuleEditor:
- Supports nesting and non-nesting modes
- Gets the available popups/views from its delegate
- Is bindings-compatible
- Supports automatic generation of NSPredicates
- Supports flexible localization through a strings file or dictionary

Please refer to NSRuleEditor.h and documentation for more info on this new class.


NSPredicateEditor

NSPredicateEditor is a subclass of NSRuleEditor specialized for working with predicates. Unlike NSRuleEditor, NSPredicateEditor does not depend on its delegate to populate its rows (and does not call the populating delegate methods). Instead, its rows are populated from its objectValue, which is an NSPredicate.

NSPredicateEditor relies on instances of a new class, NSPredicateEditorRowTemplate, which is responsible for mapping back and forth between the displayed view values and various predicates.

NSPredicateEditor exposes one property, rowTemplates, which is an array of NSPredicateEditorRowTemplates.
- (void)setRowTemplates:(NSArray *)rowTemplates;
- (NSArray *)rowTemplates;
Developers will typically configure NSPredicateEditor with some NSPredicateEditorRowTemplates, either programmatically or in Interface Builder, and then set and get NSPredicates on the NSPredicateEditor. Changes to the predicate are announced with the usual target/action mechanism.


NSMenu

New menu customization APIs

Leopard now allows applications to set a custom view for a menu item, via the following new NSMenuItem methods:
- (void)setView:(NSView *)view;
- (NSView *)view;
The custom view takes over all aspects of the menu item's drawing. Mouse event processing is handled normally for the view, including mouse down, mouse up, mouse moved, mouse entered, mouse exited, mouse dragged, and scroll wheel events. In non-sticky tracking mode (manipulating menus with the mouse button held down), the view will receive mouseDragged: events. See the header file NSMenuItem.h for more information about custom menu item views.

Animation in menu item views

Views in menu items can be animated with the usual mechanisms, such as calling - [NSView setNeedsDisplay:] or - [NSView display] in a repeating timer. But be aware that menu tracking occurs with the run loop running in NSEventTrackingRunLoopMode, so any timers you add must be set to fire while in that mode.

New delegate methods and notifications

Menus will now notify their delegates when they are opened or closed, and when they highlight or unhighlight items during menu tracking. See NSMenu.h for more information about these new delegate methods.

Removal of NSMenuItem protocol

All uses of id <NSMenuItem> have been removed from AppKit in Leopard. Applications should switch to the NSMenuItem class.

NSMenuItem attributed title truncation

In versions of Mac OS X prior to Leopard, NSMenuItems with excessively long attributed titles would be clipped against the edge of the menu. In Leopard, NSMenuItem attributed titles will be truncated by default using the "NSLineBreakByTruncatingMiddle" truncation style. You may override this by specifying a different line break mode for the NSParagraphStyle attached to the attributed title string.

validateItem: no longer called

Historically, AppKit has called the validateItem: method to validate menu items, if validateMenuItem: and validateUserInterfaceItem: were not implemented. This behavior was never documented and it is now disabled for applications built on Leopard. Applications that rely on on validateItem: should switch to validateMenuItem: or validateUserInterfaceItem:.

validateMenuItem: only called on matching key equivalents

Before Leopard, typing a key equivalent would cause AppKit to attempt to validate every menu item in the menu (via validateMenuItem:). As an optimization, AppKit will now only validate the item with the matching key equivalent. Applications should use NSMenu's delegate methods to lazily populate a menu.

Command key = treated like +

As a special case, if no menu item claims ⌘= as a key equivalent, then typing ⌘= will trigger any ⌘+ key equivalent, if the pressed = key is shared with the + key. For example, on a US keyboard layout, pressing the "=" key adjacent to the "-" key on the number row will trigger any ⌘+ key equivalent, but the "=" key above the keypad will not. If the keyboard layout does not have any "+" and "=" characters on the same key, this does not apply.

Key equivalent uniqueing

AppKit tries to ensure that multiple menu items do not have the same key equivalent, because otherwise the user might accidentally invoke one while expecting to invoke the other. This is called key equivalent uniqueing. In Tiger, popup button menus were uniqued with the main menu (and in Leopard, this has been extended to also cover segmented controls). However, menu items that are thought to be aliases of one another can now share the same key equivalent, in Leopard. (Menu items are considered to be an aliases if they have the same action). Thus, in Leopard, you can have "Bold" in a popup button and also in the main menu, and both will show ⌘B as the key equivalent.

Disabled key equivalents passed through

Prior to Leopard, key equivalents corresponding to disabled menu items would be ignored. In Leopard, your application now has a chance to handle these. For example, a key equivalent for control-K on a disabled menu item will no longer block the emacs shortcut in an NSTextView, in Leopard.

ß support in key equivalents

The German sharfes s character (ß) is now supported as a key equivalent.

Menu Item Key Equivalents in non-Roman Scripts

In Tiger and earlier, key equivalents were incorrectly interpreted as follows: Characters were extracted as MacRoman, and the resulting values were interpreted as if they were in the application encoding.  This was not a problem in apps running with the MacRoman character encoding, but would cause problems in other cases. (The default character encoding of apps often depends on the user's localization choice.)

For example, specifying a key equivalent of the backslash @"\" (U+005C) would result in a yen sign key equivalent (U+00A5) when running under a Japanese localization, because the backslash value in MacRoman matches the yen value in MacJapanese: both are 0x5C in the respective character sets.  This was the only way to obtain a yen key equivalent in Tiger.

In Leopard, key equivalents and character sets are handled correctly.  To specify a yen key equivalent, specify the Unicode string containing yen (U+00A5).

For binary compatibility, Leopard will revert to Tiger's behavior for applications linked before Leopard.  When updating your application for Leopard, you should ensure that, when running on Leopard, your key equivalent string contains the characters you want, instead of the MacRoman characters that match your character's code points in the application encoding.

State images implemented

The NSMenuItem methods setOnStateImage:, setOffStateImage:, and setMixedStateImage: now work as documented.

No CMM plugins in 64-bit

NSMenu does not attempt to load Contextual Menu Manager plugins in 64-bit apps. There is no public interface for creating 64-bit CMM plugins in Leopard.

Pre-existing overrides of -[NSMenuItem isHidden]

During testing, some apps were found to have pre-existing implementations of -[NSMenuItem isHidden] that interfered with the new Leopard API of the same name. For compatibility reasons, AppKit will not call -[NSMenuItem isHidden] on apps built on Tiger or earlier. When you build your app on Leopard, AppKit will call your method and you may see strange behavior, such as menus disappearing. We recommend that you do not override -[NSMenuItem isHidden], and remove any existing overrides at the point that you build on Leopard.

Titles of Menus in the Menubar

Consider the application's main menu, an instance of NSMenu. That menu contains NSMenuItems, such as the File menu item, and the File menu item has a submenu of type NSMenu containing items such as New, Open, etc.

In Tiger, the initial label appearing in the menu bar was taken from the submenu's title. But due to a bug, changes to this menu's title did not affect the menu bar; instead, the parent item's title was used instead. So for example, the title of the File submenu determines the initial label, but to change the the label, you must modify the title of the File item itself.

For compatibility, Leopard preserves this behavior for apps built on Tiger. However, apps built on Leopard will find that the menubar consistently reflects the titles of the submenus. The titles of the items themselves in the main menu are ignored. For maximum compatibility with both Tiger and Leopard, you should set both the title of a main menu item and the title of its submenu to the same thing.

This note only applies to items that are within the NSApplication's mainMenu, and their immediate submenus. The titles of other menus have no effect.

-[NSApplication currentEvent] set when menu tracking ends

For applications linked on or after Leopard, -[NSApplication currentEvent] will reflect the event that caused menu tracking to end during the action of the selected menu item.

representedObject in NSPopUpButtonCell and NSMenuItemCell

In Leopard, NSMenuItemCell and NSPopUpButtonCell forward both setRepresentedObject: and representedObject to their current NSMenuItem. (Prior to Leopard, NSMenuItemCell and NSPopUpButtonCell would forward representedObject, but not setRepresentedObject:)

NSPopUpButtonCell setImagePosition:

NSPopUpButtonCell now respects the following image positions: NSImageOnly, NSImageLeft, NSImageRight, NSImageOverlaps. Prior to Leopard, NSPopUpButtonCell always drew with the NSImageLeft position.

Unbordered NSPopUpButtonCells

The layout of the text in unbordered popup button cells has been modified to more closely match that of NSButtonCell. For applications linked before Leopard, the layout will be preserved in some cases.

NSPopupButton Content Placement Tag binding option

The content bindings for NSPopupButton have a new option, Content Placement Tag. This provides a way of mixing static menu items with dynamically generated menu items in a popup. When this option is set to a non-zero integer value, the content bindings will only put dynamic content in place of the one menu item in the popup whose tag value matches the option value.

The typical use for this is to place some dynamically generated menu items in one part of the popup, and the follow or precede them with a menu separator and a static "action" menu item.

NSStatusItem

For consistency with NSCell and NSControl, -[NSStatusItem sendActionOn:] now returns the old mask.


NSToolbar

NSToolbar - Interface Builder support

Interface Builder 3 supports creating toolbars and toolbar items. However, you may wish to provide additional toolbar items programatically. To accomplish this, connect the delegate outlet of the NSToolbar to your desired delegate, and implement the NSToolbar delegate methods normally. The default and allowed item identifiers will be the union of those created in Interface Builder and those returned by your delegate.

NSToolbar - Show/Hide menu items

In versions of Mac OS X prior to Leopard, interface items, including menu items, that had toggleToolbarShown: set as their action would have their titles changed to "Show Toolbar" or "Hide Toolbar." For applications linked on or after Leopard, AppKit will only flip "Show Toolbar" to "Hide Toolbar" (or their localized variations) and vice versa, as appropriate. The empty title will also be modified. Nonempty titles other than the localized variants of these strings must be managed by your application.

NSToolbar - Key equivalents can match in toolbars

Before Leopard, only NSPopUpButtons in toolbars could respond to key equivalents. In Leopard, AppKit now respects the key equivalents of all controls in (visible) toolbars, not just popup buttons.

NSToolbar - NSToolbarItem default sizes

As of Leopard, if you call setView: on an NSToolbarItem without having called setMinSize: or setMaxSize:, the toolbar item will set its minimum and maximum size equal to the view's frame size.

NSToolbar - View archival

In Tiger, NSToolbar would always "copy" your toolbar item's view when displaying it in the customization palette with an NSKeyedArchiver. In Leopard, NSToolbar will only copy your view if you set the view on two different toolbar items at once. For example, say you allocate exactly one view (perhaps in a nib) and always pass it to -[NSToolbarItem setView:] in your toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar: method. If that view is in an active toolbar item, and you display the customization palette, NSToolbar will copy that view once. If that view is not in an active toolbar item and then you display the customization palette, NSToolbar will not copy the view for the customization palette, but will copy that view at the point the user drags the corresponding toolbar item from the palette into the toolbar.

If you always ensure that you pass fresh views into setView:, then NSToolbar will never copy the view.

NSToolbar - mouseDownCanMoveWindow

Previous to Leopard, only textured and unified windows were draggable by their toolbar. In Leopard, all windows are draggable by their toolbars. Apps that placed custom views in toolbars and did not override isOpaque or mouseDownCanMoveWindow may find that their views unexpectedly become draggable in addition to responding to clicks. To prevent this, the mouseDownCanMoveWindow is considered to return NO if all of the following are true:

- The app was linked on Tiger or earlier.
- The view is in a toolbar item.
- The view does not override mouseDownCanMoveWindow.
- The window is not textured or unified title/toolbar.


NSSound

NSSound has additional features on Leopard and later. These include the ability to get the duration of a sound, change the volume of a sound, set and get the playback location within the sound, and cause a sound to loop. See the documentation or comments within the NSSound.h header for more about these new APIs.

In Tiger, NSSound would willingly create a "sound" for any valid Quicktime file, including images. In Leopard, NSSound's init methods will now return nil for files that do not have a sound track.


NSSpeechSynthesizer

NSSpeechSynthesizer now provides complete access to the full power of Apple's synthesizer, including full access to third-party synthesizers compatible with Apple's Speech Synthesis framework.  Developers can now get and set individual synthesizer properties, pause and continue speech, stop speech at specific boundaries, conveniently set rate and volume properties, specify external dictionaries and receive additional callbacks for errors and synchronization events. Cocoa developers that formerly needed to use the Carbon Speech Synthesis API to gain access to certain synthesizer features should now be able to use the NSSpeechSynthesizer class instead.

Also new for Leopard is Alex, an English voice that leverages advanced Apple technology to deliver natural intonation even at very fast speaking rates.


NSViewController

A new class, NSViewController, has been added to the AppKit in Mac OS 10.5. It serves roughly the same purpose as NSWindowController, but for views instead of windows. It:
• Does the same sort of memory management of top-level objects that NSWindowController does, taking the same care to prevent reference cycles when controls are bound to the nib file's owner that NSWindowController began taking in Mac OS 10.4.
• Has a generic "represented object" property, to make it easy for you to establish bindings in the nib to an object that isn't yet known at nib-loading time or readily available to the code that's doing the nib loading.
• Has an implementation of the key-value binding NSEditor informal protocol, so that objects that own view controllers can easily make bound controls in the views commit or discard the changes the user is making.
• Has a "title" property, because we expect this to be used in many situations where the user is given the opportunity to select from several named views.

NSViewController is meant to be very reusable. For example, as described below, NSPageLayout's and NSPrintPanel's -addAccessoryController: methods each take a view controller, and set the represented object to the NSPrintInfo that is to be shown to the user. When the user dismisses a printing panel, NSPageLayout and NSPrintPanel each send NSEditor messages to each accessory view controller to ensure that the user's changes have been committed or discarded properly. The titles of the accessories are gotten from the view controllers and shown to the user in pulldown menus that the user can choose from. If your application needs to dynamically associate relatively complex views with the objects that they present to the user, you might be able to reuse NSViewController in similar ways.

NSViewController is a subclass of NSResponder, but view controllers never make themselves the next responders of the controlled views. It's the responsibility of the object that puts the controlled view in a window to insert the view controller in the responder chain if that would be worthwhile. For example, after getting the view from a view controller and adding it to a superview with -[NSView addSubview:], you can set the subview's next responder to the view controller, and then set view controller's next responder to the superview.


NSPageLayout and NSPrintPanel Accessory View Enhancements

NSPageLayout and NSPrintPanel have always had -setAccessoryView: methods that allow you to specify custom panes to be shown in page setup and print panels, respectively. However, there has been no way to specify the corresponding title that should appear in the panel's pop-up menu of panes. There has also been no way to associate summary text that should be shown for the pane's custom print settings in the print panel, or add more than one such pane to a panel. Lastly, with the introduction of built-in preview to NSPrintPanel in Mac OS 10.5 (described in the next section), we must provide a way for you to trigger the redrawing of the preview when the user changes printing parameters that you present to the user in accessory views.

New methods have been added to the NSPageLayout class to take advantage of the new NSViewController class:
- (void)addAccessoryController:(NSViewController *)accessoryController;
- (void)removeAccessoryController:(NSViewController *)accessoryController;
- (NSArray *)accessoryControllers;
When the page setup panel is presented to the user each accessory controller is automatically sent a -setRepresentedObject: message with this object's NSPrintInfo. Each controller is also automatically sent a -title message. If that returns nil the application's short name is used in the popup menu that lets the user choose an accessory view.

Slightly different new methods have also been added to the NSPrintPanel class:
- (void)addAccessoryController:(NSViewController<NSPrintPanelAccessorizing> *)accessoryController;
- (void)removeAccessoryController:(NSViewController<NSPrintPanelAccessorizing> *)accessoryController;
- (NSArray *)accessoryControllers;
These are very similar to their NSPageLayout equivalents, except the accessory controller must also conform to the new NSPrintPanelAccessorizing protocol, which has just two methods:
- (NSArray *)localizedSummaryItems;
Return the text that summarizes the settings that the user has chosen using this print panel accessory view and that should appear in the summary pane of the print panel. It must be an array of dictionaries (not nil), each of which has an NSPrintPanelAccessorySummaryItemNameKey entry and an NSPrintPanelAccessorySummaryItemDescriptionKey entry whose values are strings. A print panel acccessory view must be KVO-compliant for "localizedSummaryItems" because NSPrintPanel observes it to keep what it displays in its Summary view up to date. (In Mac OS 10.5 there is no way for the user to see your accessory view and the Summary view at the same time, but that might not always be true in the future.)
- (NSSet *)keyPathsForValuesAffectingPreview;
Return the key paths for properties whose values affect what is drawn in the print panel's built-in preview. NSPrintPanel observes these key paths and redraws the preview when the values for any of them change. For example, if you write an accessory view that lets the user turn printing of page numbers on and off in the print panel you might provide an implementation of this method that returns a set that includes a string like @"pageNumbering", as in TextEdit's PrintPanelAccessoryController class. This protocol method is optional because it's not necessary if you're not using NSPrintPanel's built-in preview, but if you use preview you almost certainly have to implement this method properly too.

Because of the requirements of this protocol, which are dictated by the realities of providing a good user interface when customizing the print panel, you must always subclass NSViewController when adding a new-style accessory view to a print panel.

The new NSPrintPanelAccessorySummaryItemNameKey and NSPrintPanelAccessorySummaryItemDescriptionKey strings are for use by implementations of NSPrintPanelAccessorizing's -localizedSummaryItems method.

The -setAccessoryView: and -accessoryView methods are now deprecated in both NSPageLayout and NSPrintPanel.

Also deprecated are NSPageLayout's -readPrintInfo and -writePrintInfo methods, and NSPrintPanel's -updateFromPrintInfo and -finalWritePrintInfo methods. They were never very useful. NSViewController provides the functionality those methods were supposed to provide; you can implement an override of the -view method to make your accessory view's UI consistent with the print info to be presented, and overrides of the KVB -commitEditing and -commitEditingWithDelegate:didCommitSelector:contextInfo: methods to make the presented print info consistent with the values showing in your accessory view.

New NSPrintPanel Methods to Control Preview and Which Standard Controls Appear

in Mac OS 10.5 a new preview feature has been added to the AppKit's printing system. The print panel now has a view that shows the user an image of the pages to be printed. It is on by default, but you can turn it off in your application. See the backward binary compatibility note at the end of this section for more information.

In many applications it is not appropriate to present page setup panels to the user, or even include a Page Setup... item in the File menu, but there has been no other easy way to let the user specify page setup parameters to be used when printing. (New UI advice: if your application doesn't persistently store page setup parameters on a per-document basis, or have some mechanism to associate them with whatever other kind of large-scale objects your application may deal with, it probably shouldn't have a page setup panel at all.) Also, some applications need to present print panels that don't include the standard fields for letting the user specify the number of copies or the range of pages to be printed.

So, In Mac OS 10.5, a new enumeration and new methods have been added to the NSPrintPanel class so that you can control previewing and what standard controls appear in the print panel. Please see the header file and documentation for info on these options.
enum {
NSPrintPanelShowsCopies = 0x01,
NSPrintPanelShowsPageRange = 0x02,
NSPrintPanelShowsPaperSize = 0x04,
NSPrintPanelShowsOrientation = 0x08,
NSPrintPanelShowsScaling = 0x10,
    NSPrintPanelShowsPageSetupAccessory = 0x100,
    NSPrintPanelShowsPreview = 0x20000
};
typedef NSInteger NSPrintPanelOptions;
- (void)setOptions:(NSPrintPanelOptions)options;
- (NSPrintPanelOptions)options;
In Mac OS 10.5 an -options message sent to a freshly-created NSPrintPanel will return (NSPrintPanelShowsCopies | NSPrintPanelShowsPageRange) unless it was created by an NSPrintOperation, in which case it will also return NSPrintPanelShowsPreview. To allow your application to take advantage of controls that may be added by default in future versions of Mac OS X, get the options from the print panel you've just created, turn on and off the flags you care about, and then set the options.

Backward binary compatibility note: The behavior described above applies to applications that are linked against Mac OS 10.5 or later. In any application linked against Mac OS 10.4 or earlier, the NSPrintPanelShowsPreview option is ignored if the application has set a print panel accessory view. Until Mac OS 10.5 there hasn't been any API that would allow you to cause the print preview to be redrawn when the user changes print settings using an accessory view, and if the print preview doesn't redraw then it's showing inaccurate information, and that's worse than no preview at all.

Other NSPrintPanel Enhancements

So that you can change the title of the default button in a print panel from "Print" to something else, two new methods have been added to NSPrintPanel:
- (void)setDefaultButtonTitle:(NSString *)defaultButtonTitle;
- (NSString *)defaultButtonTitle;
The title of the default button in the print panel. You can override the standard button title, "Print," when you're using an NSPrintPanel in such a way that printing isn't actually going to happen when the user presses that button.

So that you can change the help anchor for the question mark button in a print panel to point to something customized for your application, two other new methods have been added to NSPrintPanel:
- (void)setHelpAnchor:(NSString *)helpAnchor;
- (NSString *)helpAnchor;
The HTML help anchor for the print panel. You can override the standard anchor of the print panel's help button.

NSPrintPanel's -runModal method always uses the current NSPrintOperation's NSPrintInfo, so there has been no way to present an application-modal panel that uses any other NSPrintInfo. In Mac OS 10.5 a new method has been added to fix that:
- (NSInteger)runModalWithPrintInfo:(NSPrintInfo *)printInfo;
The default implementation of -runModal now simply invokes [self runModalWithPrintInfo:[[NSPrintOperation currentOperation] printInfo]].

An accessor for the NSPrintInfo that's being presented to the user for editing has also been added:
- (NSPrintInfo *)printInfo;
A simple accessor. Your -beginSheetWithPrintInfo:... delegate can use this so it doesn't have to keep a pointer to the NSPrintInfo elsewhere while waiting for the user to dismiss the print panel.

Access to Underlying Core Printing Objects from NSPrintInfo

In previous versions of Mac OS X there has been no public way to get the Core Printing (previously known as "Printing Manager") objects that an NSPrintInfo is actually built on top of. To make it easy for you do to exactly the same things that the PMPrintSettingsGetValue()/PMPrintSettingsSetValue() functions added in Mac OS 10.4 let you do, a new method has been added to NSPrintInfo in Mac OS 10.5. The most immediate problem that this method solves is that there has been no way for your accessory views to put settings in a place where they can be saved and restored by the printing systems presets mechanism:
- (NSMutableDictionary *)printSettings;
The print info's print settings. You can put values in this dictionary to store them in any preset that the user creates while editing this print info with a print panel. Such values must be property list objects. You can also use this dictionary to get values that have been set by other parts of the printing system, like a printer driver's print dialog extension (the same sort of values that are returned by the Carbon Printing Manager's PMPrintSettingsGetValue() function). Other parts of the printing system often use key strings like "com.apple.print.PrintSettings.PMColorSyncProfileID" but dots like those in key strings wouldn't work well with KVC, so those dots are replaced with underscores in keys that appear in this dictionary, as in "com_apple_print_PrintSettings_PMColorSyncProfileID". You should use the same convention when adding entries to this dictionary.

Because there is a substantial amount of functionality exposed by Core Printing API that is not generally applicable enough to be exposed by AppKit API, new methods have been added to NSPrintInfo in Mac OS 10.5 to allow access to the underlying Core Printing objects:
- (void * /* PMPrintSession */)PMPrintSession;
- (void * /* PMPageFormat */)PMPageFormat;
- (void * /* PMPrintSettings */)PMPrintSettings;
Return a Core Printing PMPrintSession, PMPageFormat, or PMPrintSettings object, respectively. The returned object is always consistent with the state of the NSPrintInfo at the moment the method is invoked, but isn't necessarily updated immediately if other NSPrintInfo methods like -setPaperSize: and -setPaperOrientation: are invoked. The returned object will always be valid (in the Core Printing sense). If you set any values in the returned PMPageFormat or PMPrintSettings you should afterward invoke -updateFromPMPageFormat or -updateFromPMPrintSettings, respectively. You don't also have to call PMSessionValidatePageFormat() or PMSessionValidatePrintSettings() if you do that. You should not call PMRelease() for the returned object, except of course to balance any calls of PMRetain() you do.
- (void)updateFromPMPageFormat;
- (void)updateFromPMPrintSettings;
Given that the NSPrintInfo's PMPageFormat or PMPrintSettings has been changed by something other than the NSPrintInfo itself, updates the NSPrintInfo to be consistent.

NSPrintInfo's Key-Value Coding and Key-Value Observing Compliance

Despite what the comment for -[NSPrintInfo printSettings] in <AppKit/NSPrintInfo.h> says, NSPrintInfo's KVC/KVO-compliance is not really complete enough to be useful in Mac OS 10.5. You can add a key-value observer for a key path to an NSPrintInfo but, for example, the observer won't be consistently notified of changes made by the user when the NSPrintInfo is being presented by an NSPrintPanel.

NSPrintOperation Enhancements

In previous versions of Mac OS X the print job title that the printing system uses has been gotten by invoking -[NSView(NSPrinting) printJobTitle:]. Because it is often not programmatically convenient to make such information available to printed views, new methods have been added to NSPrintOperation in Mac OS 10.5, so that the code that creates the print operation can simply set the print job title right away, and not have to leave it somewhere the printed view can find it:
- (void)setJobTitle:(NSString *)jobTitle;
- (NSString *)jobTitle;
If a job title is set it overrides anything that might be gotten by sending the printed view an [NSView(NSPrinting) printJobTitle] message.

In previous versions of Mac OS X the -currentPage method has allowed you to find out exactly which page is being printed during the running of a print operation, but there has been no easy way to determine how many pages the document being printed has. In Mac OS 10.5 a new method has been added to let you do that:
- (NSRange)pageRange;
The first page number might not be 1, depending on what the printed view returned when sent an -[NSView(NSPrinting) knowsPageRange:] message.

Support for Multiple Page Orientations per Print Operation

In Mac OS 10.5 you can now change the orientation of pages while a job is being printed. To do so your printed view must do its own pagination, and indicate so by returning YES when sent -knowsPageRange: messages. Then, when sent -rectForPage: messages, it may change the orientation of the current print operation's print info, and Cocoa will heed the change. For example: [[[NSPrintOperation currentOperation] printInfo] setOrientation:theNewOrientation].

Deprecated NSPrintOperation Methods, and a Bug Fix in -[NSPrintOperation printPanel]

In Mac OS 10.5 the -setAccessoryView: and -accessoryView methods are now also deprecated in NSPrintOperation.

Also deprecated are the -setJobStyleHint: and -jobStyleHint: methods. Instead of sending one of those messages to an NSPrintOperation, just invoke -[NSPrintOperation printPanel] and send them to the returned NSPrintPanel instead. -[NSPrintOperation printPanel] has been updated to create and return a new print panel if none has been set yet. (It would usually just return nil before.)

Bug Fixes in -[NSPrintInfo paperName], -[NSPrintInfo setPaperName:], and -[NSPrinter pageSizeForPaper:]

In Mac OS 10.2 through Mac OS 10.4 there was a bug in -[NSPrintInfo paperName] that would cause it to return incorrect paper names. For example, it might return "na-letter" or "Letter" when it should return "LetterSmall" (remember, the paper "names" returned by -paperName are not for showing to users; use -localizedPaperName to get those). Likewise, -[NSPrintInfo setPaperName:] could set a paper that had the same size as the named paper but a different name. These problems were particularly noticeable when a printer supports multiple "papers" that have the same sizes but different imageable areas. The bug has been fixed in Mac OS 10.5.

In earlier versions of Mac OS X -[NSPrinter pageSizeForPaper:] only worked when passed strings that are paper names, not paper IDs, in the senses established by the Core Printing API. In Mac OS 10.5 this method now always works when passed paper IDs (the sort of string now always returned by -[NSPrintInfo paperName]). For backward binary compatibility it returns the same values that it would have in Mac OS 10.4 if passed a paper name.

Bug Fixes in NSPrintOperation/NSPrintPanel Cancellation

In earlier versions of Mac OS X there was a bug in which a print job would be sent to the printer even though the user had hit the Cancel button in the print progress panel, if rendering of the last page of the job had already begun. This bug has been fixed in Mac OS 10.5.

There was also a bug in which invoking [[[NSPrintOperation currentOperation] printInfo] setJobDisposition:NSPrintCancelJob] from within overrides of NSView(NSPrinting) methods did not prevent the part of the print job that had already been rendered from being sent to the printer. This bug has also been fixed in Mac OS 10.5. You can now programmatically cancel the current print operation in your overrides of any of the NSView(NSPrinting) methods.

In earlier versions of Mac OS X there was no way to distinguish between user cancellation and failure when invoking -[NSPrintOperation runOperationModalForWindow:delegate:didRunSelector:contextInfo:] or -[NSPrintPanel beginSheetWithPrintInfo:modalForWindow:delegate:didEndSelector:contextInfo:]. In Mac OS 10.5 these methods always set the job disposition of the presented print info to NSPrintCancelJob when the user has cancelled the print panel, just as -[NSPrintOperation runOperation] and -[NSPrintPanel runModal] always have. For backward binary compatibility this is only done if the application is linked against Mac OS 10.4 or earlier. In the case of NSPrintOperation the "presented print info" is the one that can be gotten with -[NSPrintOperation printInfo], not the one that was passed in when the NSPrintOperation was created.

There was a bug in which an NSPrintOperation created with a print info whose job disposition was NSPrintCancelJob would never result in output, regardless of what button the user used to dismiss the print panel. This bug has been fixed.

Advice for Developers Working with Printing Margins

The "Printer Margins" in the Custom Page Sizes panel are confusingly named. They are not margins in the NSPrintInfo sense, or in the sense of Microsoft Word, AppleWorks, or any app that lets the user set a document's page margins. They are the widths and heights of the areas of the page that lie outside of the imageable area for the paper size. In other words, the Custom Page Sizes panel is giving you the opportunity to simulate hardware limitations when defining a new paper size. You can use the -[NSPrintInfo imageablePageBounds] method to get the area of page that is surrounded by the printer margins.


Support for Uniform Type Identifiers (UTIs) in NSDocument-Based Applications

If your application requires Mac OS 10.5, it may stop using these legacy Info.plist keys in its CFBundleDocumentTypes entries:
CFBundleTypeExtensions
CFBundleTypeMIMETypes
CFBUndleTypeOSTypes
NSExportableAs

It may instead use the LSItemContentTypes and (new for Mac OS 10.5) NSExportableTypes keys, and declare the corresponding UTIs as appropriate in its Info.plist. Declaration of UTIs in Info.plist files is described by <http://developer.apple.com/macosx/uniformtypeidentifiers.html>. For each CFBundleDocumentTypes entry that has an LSItemContentTypes subentry, sibling subentries with the keys listed above are ignored. (Actually Cocoa's Info.plist parsing has always ignored CFBundleTypeMIMETypes subentries. In Mac OS 10.5 it continues to. LaunchServices pays attention to them though, except when there's an LSItemContentTypes sibling. So, in Mac OS 10.5 Cocoa and LaunchServices follow the same rules about ignoring LSItemContentTypes siblings.)

If your application uses the LSItemContentTypes key it must also use the NSExportableTypes key where applicable. NSExportableTypes entries serve the same purpose as NSExportableAs entries, and are likewise subentries of CFBundleDocumentTypes entries, but their values are arrays of UTIs instead of arrays of old-style free-form type names.

Use of these keys becomes optional:
CFBundleTypeName
CFBundleTypeIconFile
For each CFBundleDocumentTypes entry that has an LSItemContentTypes subentry you can provide subentries using these keys to override the default icon and kind string that would otherwise result from UTI declarations. As has always been the case, any use of CFBundleTypeName should be accompanied by an entry in the application's InfoPlist.strings files.

The meanings of CFBundleTypeRole and NSDocumentClass subentries have not changed in Mac OS 10.5.

For each CFBundleDocumentTypes entry that has an LSItemContentTypes subentry, the UTIs are used as programmatic type names by NSDocument and NSDocumentController, as described below, instead of the value of any CFBundleTypeName subentry that might also be present.

For backward binary compatibility, none of this new behavior takes affect if the application is linked against Mac OS 10.4 or earlier. A CFBundleDocumentTypes entry that has no LSItemContentTypes subentry at all has the same meaning to Cocoa as in Mac OS 10.4.

Debugging tip: In Mac OS 10.5 you can find out what NSDocumentController thinks it's found in your application's Info.plist by executing 'print-object [[NSClassFromString(@"NSDocumentController") sharedDocumentController] _typeDescriptions]' in gdb (using the Xcode Debugger Console, for instance). Do not attempt to invoke or override -_typeDescriptions in your application. It is there just for this debugging purpose, and may disappear at any time.

Shipping tip: If you want to take advantage of UTIs in your application but have it still run on both Mac OS 10.4 and Mac OS 10.5, you can merely add LSItemContentTypes (and NSExportableTypes, where appropriate) subentries to your Info.plist, and then update your overrides of NSDocumentController and NSDocument methods so that they recognize UTIs as type names in addition to the sort of document types names that were always used in Mac OS 10.4. Be careful to add LSItemContentTypes subentries to all of the app's CFBundleDocumentTypes Info.plist entries though, or things could get more complicated. See the description of -typeForContentsOfURL:error:'s new behavior down below for instance.

Support for UTIs in NSDocumentController

In Mac OS 10.5 NSDocumentController supports UTIs. In the following paragraphs an "app-declared" UTI is one that is declared in a well-formed LSItemContentTypes subentry of a well-formed CFBundleDocumentTypes Info.plist entry, in an application that is linked against Mac OS 10.5 or later. A "recognized" UTI is app-declared or conforms to one of the app-declared UTIs.

None of the NSDocumentController methods that were deprecated in Mac OS 10.4 have been updated to handle UTIs properly. You have to stop invoking and overriding deprecated methods to take advantage of UTIs in your application.

-makeUntitledDocumentOfType:error:, -makeDocumentWithContentsOfURL:ofType:error:, and -makeDocumentForURL:withContentsOfURL:ofType:error: all now accept recognized UTIs as type strings, in addition to the sort of document type names that were accepted in Mac OS 10.4. The latter two methods have also been updated to properly handle unrecognized types too. (Because -typeForContentsOfURL:error: might now return an urecognized type.)

-URLsFromRunningOpenPanel now, for each CFBundleDocumentTypes entry that declares an openable document type (as in, has a CFBundleTypeRole of Editor or Viewer, as in Mac OS 10.4) with app-declared UTIs, passes those UTIs into -runModalOpenPanel:forTypes:. For each CFBundleDocumentTypes that declares an openable document without recognized UTIs it still passes file name extensions and encoded HFS file types as in Mac OS 10.4.

-runModalOpenPanel:forTypes: nows accepts all valid UTIs in the array of type strings, in addition to the file name extensions and encoded HFS file types that were accepted in Mac OS 10.4.

-defaultType chooses a CFBundleDocumentTypes entry and considers that document type to be the default type, as in Mac OS 10.4. Once it has made that choice it now returns the first app-declared UTI for that type, if there are any, or a document type name, of the sort returned in Mac OS 10.4, if not. (So the order of elements in the LSItemContentTypes array does matter, just as the order of elements in the CFBundleDocumentTypes array always has.)

-typeForContentsOfURL:error: now uses -[NSWorkspace typeOfFile:error:] to find out the UTI of the file located by the URL. (So it might return a UTI that is not recognized. AppKit's own invocations of it take that fact into account.) For backward binary compatibility it however first tries the same thing that it did in Mac OS 10.4 (invoke -typeFromFileExtension:, possibly twice, passing an HFS file type string for the second invocation) if there are any CFBundleDocumentTypes Info.plist entries that don't have LSItemContentTypes subentries.

-documentClassForType: now accepts any recognized UTI as the type string. As in Mac OS 10.4 it sends a +readableTypes message to each class named in the results of invoking -documentClassNames, and returns the first class whose readable types include one that matches the passed-in type. "Matches" for a UTI means "conforms to," instead of merely "is equal to." (So this method will work even when passed a UTI that is not explicitly declared in the application's Info.plist, but conforms to one that is.)

-displayNameForType: now accepts all valid UTIs as the type string, in addition to the sort of document type names that were accepted in Mac OS 10.4. It returns nil when passed an invalid UTI. For backward binary compatibility it continues to not return nil when passed a non-UTI.

-fileExtensionsFromType: and -typeFromFileExtension: have not changed, but are being deprecated. -fileExtensionsFromType: does not work when passed a UTI. -typeFromFileExtension: only works when passed a file name extension used in a CFBundleDocumentTypes entry that does not have an LSItemContentTypes subentry. In general, if each of the application's CFBundleDocumentTypes Info.plist entries has a valid LSItemContentTypes subentry, and the application doesn't invoke deprecated methods like -fileNamesFromRunningOpenPanel, then these methods will never be invoked from within Cocoa.

Support for UTIs in NSDocument

In Mac OS 10.5 NSDocument's handling of types is consistent with NSDocumentController. Every non-deprecated NSDocument method that takes a type: or ofType: argument now accepts recognized UTIs as type strings, in addition to the sort of document type names that were accepted in Mac OS 10.4. -setFileType: and -fileType: don't actually interpret the file type name in any way, so they work fine with UTIs.

None of the NSDocument methods that were deprecated in Mac OS 10.4 have been updated to handle UTIs properly. You have to stop invoking and overriding deprecated methods to take advantage of UTIs in your application.

+readableTypes, +writableTypes, and -writableTypesForSaveOperation: all now return UTIs for CFBundleDocumentTypes entries with app-declared UTIs, and document types of the sort that were returned in Mac OS 10.4 for those that don't.

+isNativeType: now accepts all valid UTIs as the type string, in addition to the sort of document type names that were accepted in Mac OS 10.4. It will return YES if a passed-in UTI conforms to a recognized UTI for the document class in question, NO otherwise.

A new method has been added to NSDocument, because -[NSDocumentController fileExtensionsFromType:] is being deprecated:
- (NSString *)fileNameExtensionForType:(NSString *)typeName saveOperation:(NSSaveOperationType)saveOperation;
For a specified type, and a particular kind of save operation, return a file name extension that can be appended to a base file name. The default implementation of this method invokes [[NSWorkspace sharedWorkspace] preferredFilenameExtensionForType:typeName] if the type is a UTI or, for backward binary compatibility with Mac OS 10.4 and earlier, invokes [[NSDocumentController sharedDocumentController] fileExtensionsFromType:typeName] and chooses the first file name extension in the returned array if not.

You can override this method to customize the appending of extensions to file names by NSDocument. In Mac OS 10.5 it's only invoked from two places within Cocoa: 1) -autosaveDocumentWithDelegate:didAutosaveSelector:contextInfo: uses this method when creating a new file name for the autosaved contents. 2) -[NSDocument(NSScripting) handleSaveScriptCommand:] uses this method when adding an extension to the file name specified by a script. In all other cases the name of any file being saved will have been fully specified by the user, with the save panel (whether they know it or not).

Support for UTIs in NSPersistentDocument

In Mac OS 10.5 NSPersistentDocument's handling of types is consistent with NSDocumentController's and NSDocument's. Every NSPersistentDocument method that takes a type string argument now accepts recognized UTIs, in addition to the sort of document type names that were accepted in Mac OS 10.4.

Support for UTIs in NSOpenPanel

In Mac OS 10.5 NSOpenPanel supports UTIs. The following methods all now accept all valid UTIs as type strings, in addition to the file name extensions and encoded HFS file types that were accepted in Mac OS 10.4:
-beginSheetForDirectory:file:types:modalForWindow:modalDelegate:didEndSelector:contextInfo:
-beginForDirectory:file:types:modelessDelegate:didEndSelector:contextInfo:
-runModalForDirectory:file:types:
-runModalForTypes:
NSOpenPanel will let the user choose files whose types conform to those identified by the passed-in UTIs. So, you can let the user select any image file by passing in a UTI like public.image. Be aware however that the set of types conforming to another can be extended by any application installed on the computer, so this might not be a good idea if your application actually has to open the files the user chooses with the open panel. Typically you'll pass in UTIs for more concrete types, like public.tiff, com.adobe.pdf, or com.apple.sketch2.

Support for UTIs in NSSavePanel

In Mac OS 10.5 NSSavePanel supports UTIs. The following methods now accept or return all valid UTIs as type strings, in addition to the file name extensions that were accepted and returned in Mac OS 10.4 (encoded HFS file types have never been valid values for these methods):
-setAllowedFileTypes:
-setRequiredFileType:
-allowedFileTypes:
-requiredFileType:

Support for UTIs in NSWorkspace

In Mac OS 10.5 NSWorkspace supports UTIs. -iconForFileType: now accepts all valid UTIs as type string, in addition to the file name extensions and encoded HFS file types that were accepted in Mac OS 10.4.

Several methods have been added to NSWorkspace:
- (NSString *)typeOfFile:(NSString *)absoluteFilePath error:(NSError **)outError;
Given an absolute file path, return the uniform type identifier (UTI) of the file, if one can be determined. Otherwise, return nil after setting *outError to an NSError that encapsulates the reason why the file's type could not be determined. If the file at the end of the path is a symbolic link the type of the symbolic link itself will be returned, not the type of the linked file. You can invoke this method to get the UTI of an existing file.
- (NSString *)localizedDescriptionForType:(NSString *)typeName;
Given a UTI, return a string that describes the document type and is fit to present to the user, or nil for failure. You can invoke this method to get the name of a type that must be shown to the user, in an alert about your application's inability to handle the type, for instance.
- (NSString *)preferredFilenameExtensionForType:(NSString *)typeName;
Given a UTI, return the best file name extension to use when creating a file of that type, or nil for failure. You can invoke this method when your application has only the base name of a file that's being written and it has to append a file name extension so that the file's type can be reliably identified later on.
- (BOOL)filenameExtension:(NSString *)filenameExtension isValidForType:(NSString *)typeName;
Given a file name extension and a UTI, return YES if the file name extension is a valid tag for the identified type, NO otherwise. You can invoke this method when your application needs to check if a file name extension can be used to reliably identify the type later on. For example, NSSavePanel uses this method to validate any extension that the user types in the panel's file name field.
- (BOOL)type:(NSString *)firstTypeName conformsToType:(NSString *)secondTypeName;
Given two UTIs, return YES if the first "conforms to" to the second in the uniform type identifier hierarchy, NO otherwise. This method will always return YES if the two strings are equal, so you can also use it with other kinds of type name, including those declared in CFBundleTypeName Info.plist entries in apps that don't take advantage of the support for UTIs that was added to Cocoa in Mac OS 10.5. You can invoke this method when your application must determine whether it can handle a file of a known type, returned by -typeOfFile:error: for instance. Use this method instead of merely comparing UTIs for equality.

Support for UTIs in NSPasteboard

In Mac OS 10.5 NSPasteboard supports UTIs. Every NSPasteboard method that takes a type string or type string array argument now accepts UTIs as type strings, in addition to the sort of pasteboard type names that were accepted in Mac OS 10.4.

-types now returns an array that contains UTIs, as well as the pasteboard type names that would be returned in Mac OS 10.4.

When one of your application's pasteboard owners' -pasteboard:provideDataForType: methods is invoked it will still always be passed the same string that was specified in the promising invocation of -declareTypes:owner: or -addTypes:owner.

When -availableTypeFromArray: encounters a UTI in the type array provided to it, it will return that UTI if the exact UTI exists anywhere in the pasteboard's array of types. If no pasteboard type matches the UTI exactly, the first type on the pasteboard that conforms to the UTI will be returned.

Support for UTIs in NSView and NSWindow

Likewise, in Mac OS 10.5 NSView and NSWindow support UTIs. NSView and NSWindow's -registerForDraggedTypes: methods now accept UTIs as type strings, in addition to the sort of pasteboard type names that were accepted in Mac OS 10.4. NSView's -dragPromisedFilesOfTypes:fromRect:source:slideBack:event: method now accepts UTIs as type strings, in addition to the sort of file name extensions that were accepted in Mac OS 10.4.

For UTIs registered as dragged types, UTI conformance is checked instead of equality to determine if a dragging destination should be given a chance to handle a drag. For example, a view with the UTI kUTTypeImage registered as a dragged type will have its dragging destination methods called to handle a drag in its bounds when the dragging pasteboard contains any type that conforms to kUTTypeImage.

Support for UTIs in Services

You can now specify declared UTIs instead of pasteboard types as the elements of the NSSendTypes or NSReturnTypes arrays in the Services declaration part of an application's Info.plist.

Support for UTIs in Miscellaneous AppKit Classes

In earlier versions of Mac OS X, these four classes:
NSImage
NSImageRep
NSSound
NSAttributedString (in the NSAttributedStringKitAdditions category)

have all had pairs of methods that return either arrays of file type strings (file name extensions and encoded HFS file types) or pasteboard type strings. In Mac OS 10.5, these methods are joined by single new methods that just return arrays of UTIs. Also, NSImageRep's methods that take file type or pasteboard type strings are joined by a new method that just takes UTIs.

It's important to keep in mind when working with UTIs that mere string equality checking is not the correct way to check if the type identified by one UTI "conforms" to the type identified by another. See the description of the -[NSWorkspace type:conformsToType:] in the "Support for UTIs in NSWorkspace" section.

The follow sections contain the details of this change for each class.

Support for UTIs in NSImage

In NSImage, these new methods:
+ (NSArray *)imageTypes;
+ (NSArray *)imageUnfilteredTypes;
join these methods, which might be deprecated in a future release of Mac OS X, but are not yet:
+ (NSArray *)imageFileTypes;
+ (NSArray *)imagePasteboardTypes;
+ (NSArray *)imageUnfilteredFileTypes;
+ (NSArray *)imageUnfilteredPasteboardTypes;
(The old methods are not yet deprecated because you might still have a reason to override them, because the -initWithContentsOfFile:, -initWithContentsOfURL:, -initByReferencingFile:, -initByReferencingURL:, -initWithPasteboard:, and +canInitWithPasteboard: methods have not yet been updated to use UTIs when deciding which subclass of NSImageRep should be instantiated. The same is true of -[NSBundle(NSBundleImageExtension) pathForImageResource:].)

Support for UTIs in NSImageRep

In NSImageRep, these new methods:
+ (Class)imageRepClassForType:(NSString *)type;
+ (NSArray *)imageTypes;
+ (NSArray *)imageUnfilteredTypes;
join these methods, which might be deprecated in a future release of Mac OS X, but are not yet:
+ (Class)imageRepClassForFileType:(NSString *)type;
+ (Class)imageRepClassForPasteboardType:(NSString *)type;
+ (NSArray *)imageFileTypes;
+ (NSArray *)imagePasteboardTypes;
+ (NSArray *)imageUnfilteredFileTypes;
+ (NSArray *)imageUnfilteredPasteboardTypes;
(The old methods are not yet deprecated because you might still have a reason to override them, because the +imageRepsWithContentsOfFile:, +imageRepWithContentsOfFile:, +imageRepsWithContentsOfURL:, +imageRepWithContentsOfURL:, +imageRepsWithPasteboard:, +imageRepWithPasteboard:, and +canInitWithPasteboard: methods have not yet been updated to use UTIs when deciding which subclass of NSImageRep should be instantiated, or whether a subclass can be instantiated, in the case of the last method.)

Support for UTIs in NSSound

In NSSound, this new method:
+ (NSArray*)soundUnfilteredTypes;
replaces these deprecated methods:
+ (NSArray *)soundUnfilteredFileTypes;
+ (NSArray *)soundUnfilteredPasteboardTypes;

Support for UTIs in AppKit's NSAttributedStringKitAdditions Category on NSAttributedString

In NSAttributedString(NSAttributedStringKitAdditions), these new methods:
+ (NSArray *)textTypes;
+ (NSArray *)textUnfilteredTypes;
replace these deprecated methods:
+ (NSArray *)textFileTypes;
+ (NSArray *)textPasteboardTypes;
+ (NSArray *)textUnfilteredFileTypes;
+ (NSArray *)textUnfilteredPasteboardTypes;
The -initWithURL:options:documentAttributes:error:, -initWithPath:documentAttributes:, and -initWithURL:documentAttributes: methods have all been updated to use UTIs when appropriate. So have NSMutableAttributedString(NSMutableAttributedStringKitAdditions)'s -readFromURL:options:documentAttributes:error: and -readFromURL:options:documentAttributes: methods.


Rewritten NSDocument Safe Saving, and a Bug Fixing for Saving Documents That Change From Plain Files to File Packages

-[NSDocument writeSafelyToURL:ofType:forSaveOperation:error:] has been rewritten to use CarbonCore's new FSPathReplaceObject() function. Some kinds of metadata, like extended attributes and access control lists, will now more often be properly preserved during document saving, especially of file packages. Also, safe document saving is now a little safer, particularly when the disk being written to is full. For example, your users will no longer see their documents get renamed with a "~" on the end, and left that way, when document saving fails because there is not enough space on disk to save a new document revision.

In Mac OS 10.4 and earlier there was a bug in which NSDocument would malfunction when a document that was a plain file on disk was overwritten with a file package of the same name during a save operation. (Some applications use the same file name extension for both the flat-file and the directory-based variants of what is conceptually, as far as the user is concerned, the same file format.) This bug has been fixed in Mac OS 10.5.

NSDocument Checking for Modified Files At Saving Time

In Mac OS 10.5 -[NSDocument saveDocumentWithDelegate:didSaveSelector:contextInfo:] now checks to see if the document's file has been modified since the document was opened or most recently saved or reverted, in addition to the checking for file moving, renaming, and trashing that it has done since Mac OS 10.1. When it senses file modification it presents an alert telling the user "This document’s file has been changed by another application since you opened or saved it," giving them the choice of saving or not saving. For backward binary compatibility this is only done in applications linked against Mac OS 10.5 or later.

When updating your application to link against Mac OS 10.5, keep in mind that it's usually more appropriate to invoke one of NSDocument's -save… methods in your application code than one of the -write… methods. The -write… methods are there primarily for you to override. -saveToURL:ofType:forSaveOperation:error:, which is the method that's meant to always be invoked during document saving, invokes -setFileModificationDate: with the file's new modification date after it's been written (for NSSaveOperation and NSSaveAsOperation only).

Likewise, it's usually more appropriate to invoke one of NSDocument's -revert… methods in your application code code than one of the -read… methods. The -read… methods are there primarily for you to override. -revertToContentsOfURL:ofType:error:, which is the method that's meant to always be invoked during rereading of an open document, invokes -setFileModificationDate: with the file's modification date after it's been read.

Bug Fix in -[NSDocument isDocumentEdited], and New Constant Used with -[NSDocument updateChangeCount:]

In previous versions of Mac OS X there has been a bug in which saving a document, undoing changes, and then making an equal number of new changes would cause the document to appear unmodified. If the user closed the document it would simply be closed, with no warning about unsaved changes, which would be lost. This happened in any application in which the document did not send [self updateChangeCount:NSChangeCleared] during document saving (which you're not supposed to have to do). This bug has been fixed in Mac OS 10.5, by virtue of NSDocument now drawing a distinction between doing and redoing of changes. It no longer invokes [self updateChangeCount:NSChangeDone] when it receives an NSUndoManagerDidRedoChangeNotification. Now it invokes [self updateChangeCount:NSChangeRedone] instead. (NSChangeDone is still used for NSUndoManagerWillCloseUndoGroupNotification.) NSChangeRedone is new, and declared in <AppKit/NSDocument.h>.

For backward binary compatibility NSDocument only uses NSChangeRedone instead of NSChangeDone in applications linked against Mac OS 10.5 or later, or if -updateChangeCount: is not overridden.

Bug Fix in NSDocument for Nested Undo Manager Groups

In previous versions of Mac OS X there was a bug in which NSDocument's undo support did not take into account nested undo manager groups. Each NSDocument would merely send itself a [self updateChangeCount:NSChangeDone] message whenever it received an NSUndoManagerWillCloseUndoGroupNotification from its undo manager. This would cause it to improperly count how many changes the user had made so that, for example, making one undoable change represented by multiple actions in nested undo groups, and then undoing that change, would still show the document as modified. This problem was particularly noticeable in document-based Core Data applications, because NSManagedObjectContext uses nested undo manager groups. This has been fixed in Mac OS 10.5. NSDocument now checks the undo manager's grouping level when it receives NSUndoManagerWillCloseUndoGroupNotification, and only invokes -updateChangeCount: if the nesting level is less than two.

Bug Fix in -[NSDocument writeToURL:ofType:error:]'s Use of NSFileWrapper

In Mac OS 10.4, -[NSDocument writeToURL:ofType:error:] passed NO as the last argument when invoking -[NSFileWrapper writeToFile:atomically:updateFilenames:]. In Mac OS 10.5 it now passes YES so that the file wrapper and any file wrappers it contains have their file names updated during saving. -[NSDocument writeToFile:ofType:], which was deprecated in Mac OS 10.4, has not been updated in a similar way.

Bug Fix in NSDocument's Use of -[NSDocument autosavingFileType]

In Mac OS 10.4, -[NSDocument autosaveDocumentWithDelegate:didAutosaveSelector:contextInfo:] would invoke [self autosavingFileType] the first time a document was autosaved, create an autosaved contents file URL using the implied file name extension, and then keep using that URL for all subsequent autosaves. If -autosavingFileType was overridden to return different values at different times, this could result in inconsistencies. For example, the new version of TextEdit in Leopard that uses autosaving could end up autosaving an RTFD file package with an ".rtf" file name extension. (Because it overrides -autosavingFileType to account for attachments being added to the document.) This was a bug, and has been fixed in Mac OS 10.5. NSDocument now consistently uses the result of invoking -autosavingFileType when determining where to autosave.

Advice for Overriders of -[NSDocument autosavingFileType]

Even with the bug fixed mentioned above, overriding -autosavingFileType can result in incorrect behavior during reopening of autosaved documents if you're not careful. -[NSDocument initForURL:withContentsOfURL:ofType:error:], which is invoked during reopening of autosaved documents after a crash, takes two URLs, but only the type name of the autosaved contents file. The default implementation invokes [self setFileType:] with that type name, but that is often not the right thing to do, if -autosavingFileType had returned something other than -fileType during document autosaving. If you override -autosavingFile, you probably have to override -initForURL:withContentsOfURL:ofType:error: too, and make the override invoke -setFileType: with the type of the actual document file, after invoking super. See TextEdit's Document class for an example of how to do this.

Advice for Overriders of NSDocument Reading and Writing Methods

If you subclass NSDocument and override any of these methods for reading:

-readFromData:ofType:error:
-readFromFileWrapper:ofType:error:
-readFromURL:ofType:error:

Or any of these for writing:

-dataOfType:error:
-fileWrapperOfType:error:
-writeToURL:ofType:error:
-writeToURL:ofType:forSaveOperation:originalContentsURL:error:
-fileAttributesToWriteToURL:ofType:forSaveOperation:originalContentsURL:error:
-writeSafelyToURL:ofType:forSaveOperation:error:

Or any of the methods that were deprecated in favor of them, in Mac OS 10.4:

-dataRepresentationOfType:
-fileAttributesToWriteToFile:ofType:saveOperation:
-fileWrapperRepresentationOfType:
-initWithContentsOfFile:ofType:
-initWithContentsOfURL:ofType:
-loadDataRepresentation:ofType:
-loadFileWrapperRepresentation:ofType:
-readFromFile:ofType:
-readFromURL:ofType:
-writeToFile:ofType:
-writeToFile:ofType:originalFile:saveOperation:
-writeToURL:ofType:
-writeWithBackupToFile:ofType:saveOperation:

Don't invoke -fileURL (or -fileName, the method that was deprecated in favor if it, in Mac OS 10.4), -fileType, or -fileModificationDate from within your overrides. During reading, which typically happens during object initialization, there is no guarantee that NSDocument properties like the file's location or type have been set yet. Your overridden method should be able to determine everything it needs to do the reading from the passed-in parameters. During writing, your document may be being asked to write its contents to a different location, or using a different file type. Again, your overridden method should be able to determine everything it needs to do the writing from the passed-in parameters.

If your override cannot determine all of the information it needs from the passed-in parameters, consider overriding another method. For example, if you see the need to invoke -fileURL from within an override of -readFromData:ofType:error:, perhaps you should instead override -readFromURL:ofType:error:. For another example, if you see the need to invoke -fileURL from within an override of -writeToURL:ofType:error:, perhaps you should instead override -writeToURL:ofType:forSaveOperation:originalContentsURL:error:.

Advice for Overriders of -[NSDocument displayName]

Some applications have subclasses of NSDocument that override -displayName to customize the the titles of windows associated with the document. That is usually not the right thing to do. Use a subclass of NSWindowController, and override -[NSWindowController windowTitleForDocumentDisplayName:] instead. If even deeper customization is required override -[NSWindowController synchronizeWindowTitleWithDocumentName]. A document's display name is used in several other places where the custom value that an application might want to use as a window title is typically not appropriate:
- In error alerts that may be presented during reverting, saving, or printing of the document.
- In alerts that will be presented during document saving if the document has been moved, renamed, or put in the trash.
- In the alert that will be presented when the user attempts to close the document with unsaved changes.
- As the default value shown in the "Save As:" field of save panels.
It may be used in even more places in future releases of Mac OS X.

Advice for Overriders of -[NSDocument init]

If you subclass NSDocument and override -init, make sure your override never returns nil. When running on Mac OS 10.4 this will likely cause a crash in AppKit. In Mac OS 10.5 it will cause AppKit to present an error alert that is not very useful to the user (for example, "No document could be created."). If, for example, you want to prevent the creation or opening of documents under circumstances unique to your application, override a specific NSDocumentController method instead. Read the next section before doing so.

Advice for Overriders of Methods That Return NSErrors by Reference

In Mac OS 10.4 we published many new methods that return NSErrors. For example, in NSDocumentController:
- (id)openUntitledDocumentAndDisplay:(BOOL)displayDocument error:(NSError **)outError;
- (id)openDocumentWithContentsOfURL:(NSURL *)absoluteURL display:(BOOL)displayDocument error:(NSError **)outError;
etc. When overriding such methods take care to follow this rule: a method that takes an error:(NSError **)outError argument must, if it returns a value that signals failure (typically nil or NO), and if outError!=NULL, set the value of *outError to point to an NSError. It is not the responsibility of code that invokes such methods to nil-initialize the variable whose address is taken and passed as the error parameter, just so it can safely check to see if the variable's value is no longer nil after the invocation.

If you're overriding such a method to prevent some action, but you don't want an error alert to be presented to the user, return an error whose domain is NSCocoaErrorDomain and whose code is NSUserCancelledError. AppKit itself consistently presents NSErrors to the user with the machinery described at <http://developer.apple.com/documentation/Cocoa/Conceptual/ErrorHandlingCocoa/index.html>. Unless your application overrides AppKit's error presentation methods in novel ways, use of this machinery consistently results in invocations of -[NSApplication presentError:] or -[NSApplication presentError:modalForWindow:delegate:didPresentSelector:contextInfo:]. Both of these methods silently ignore NSCocoaErrorDomain/NSUserCancelledError errors. So, for example:
- (id)openDocumentWithContentsOfURL:(NSURL *)absoluteURL display:(BOOL)displayDocument error:(NSError **)outError {
    /* The user double-clicked on a document in the Finder or something, but we don't want to
open it yet if our application's custom licensing panel (for example) is being shown
as an application-modal dialog right now.
*/
id openedDocument = nil;
if (_licensingPanelIsShown) {
/* Defer the opening of the document until the user has dismissed the licensing panel.
*/
    ... Left as an exercise to the reader ...
        /* We're about to return nil, so we _must_ set *outError to something, unless of course outError is NULL.
Return an error that won't result in the presentation of an error alert. Regular Cocoa memory
management rules dictate that the invoker of this method is not responsible
for releasing the NSError, but of course +[NSError error:code:userInfo:] returns an autoreleased
object, so this is all correct.
*/
if (outError) {
*outError = [NSError errorWithDomain:NSCocoaErrorDomain code:NSUserCancelledError userInfo:nil];
}
} else {
/* Just do the regular Cocoa thing. We don't have to touch outError here.
NSDocumentController's implementation of this method has
to follow the rules too, so it sets *outError if it returns nil and outError!=NULL.
*/
openedDocument = [super openDocumentWithContentsOfURL:absoluteURL display:displayDocument error:outError];
}
return openedDocument;
}

Advice for Overriders of Methods that Follow the delegate:didSomethingSelector:contextInfo: Pattern

There are methods in the AppKit, especially in the NSDocument and DocumentController classes, that all have pretty much the same three parameters:
- A delegate object to be notified when the method's operation has been completed.
- The selector of a method to invoke to do the notifying.
- A "context info," which is just a value to pass back to the delegate so it can continue with a larger overall operation, free memory, etc.

Each method is this way because a sheet may be shown during the operation performed by the method. Such methods have to return before the user has dismissed the sheet (because of the way user event dispatching is done in the AppKit), when the result of the operation is still unknown. The delegate:didSomethingSelector:contextInfo: pattern is used so that the result can be passed to the object that requested the operation when the result is finally known.

You may discover a need to override one of these methods in your application. This is easy when the override has to add some custom behavior before invoking the superclass' implementation, but it's really not obvious how to write the override when the custom behavior goes after invoking the superclass' method. Here's an example of how to do that, in a subclass of NSDocument:
- (void)canCloseDocumentWithDelegate:(id)delegate
shouldCloseSelector:(SEL)shouldCloseSelector
contextInfo:(void *)contextInfo {
    /* No matter what happens, the original delegate must be messaged (to prevent memory leaks, at the
very least). Because we're not going to pass the passed-in parameters to super, we have
to record them somewhere. The easy place to record them is in the NSInvocation we're going
to create anyway to message the original delegate. The method selected by shouldCloseSelector
must have the same signature as...
           - (void)document:(NSDocument *)document shouldClose:(BOOL)shouldClose contextInfo:(void *)contextInfo;
        ...and that dictates how we build our invocation. We don't set a value for the shouldClose:
argument (atIndex:3) because we don't know the value yet.
*/
NSInvocation *originalDelegateInvocation = [NSInvocation invocationWithMethodSignature:
[delegate methodSignatureForSelector:shouldCloseSelector]];
[originalDelegateInvocation setTarget:delegate];
[originalDelegateInvocation setSelector:shouldCloseSelector];
[originalDelegateInvocation setArgument:&self atIndex:2]; // document:
[originalDelegateInvocation setArgument:&contextInfo atIndex:4]; // contextInfo:
    /* Do the regular NSDocument thing, arranging to take back control afterward. We must retain
the invocation object here because contextInfo: arguments are not automatically retained.
*/
[super canCloseDocumentWithDelegate:self
shouldCloseSelector:@selector(thisDocument:shouldClose:contextInfo:)
contextInfo:[originalDelegateInvocation retain]];
}
- (void)thisDocument:(NSDocument *)document shouldClose:(BOOL)shouldClose contextInfo:(void *)contextInfo {
NSInvocation *originalDelegateInvocation = (NSInvocation *)contextInfo;
    // Is the document about to be closed?
if (shouldClose) {
        // Here we can do all sorts of things with this document that's about to be closed.
    }
    /* A little bit of UI advice: changing the value of shouldClose here might result in confusing
behavior. For example, if the user hit the Save button in a "Do you want to save the changes..."
panel, and the save succeeded, and shouldClose is YES, canceling closing by changing
shouldClose to NO before messaging the delegate would be an odd thing to do.
*/
    // Tell the original delegate that the decision to close this document or not has been made.
[originalDelegateInvocation setArgument:&shouldClose atIndex:3];
[originalDelegateInvocation invoke];
    // Balance the retain we did up above.
[originalDelegateInvocation release];
}

Bug Fix for NSDocument/NSPersistentDocument Quitting-Time Hang When Using Bindings

In Mac OS 10.4 there was a bug in NSDocument that would cause an application to hang if:
- A document window has a control with a binding to a property of the document or, in a CoreData app, a managed object in the persistent document's managed object context.
- The user edits using the control but does not cause the editing to be committed (as in, types in an edit field but does not hit tab).
- The user tries to the quit the application.
- The user hits the Save button in the "Do you want to save the changes...?" alert that's presented.
This bug has been fixed in Mac OS 10.5.

New Behavior in NSWindowController at Window Closing Time

In previous versions of Mac OS X, each NSWindowController registered for NSWindowWillCloseNotification from its window and then did a number of things when it got the notification if it had a document (like removing itself from the document's window controllers and trying to close document). This way of doing things caused several problems, including:
• Other recipients of NSWindowWillCloseNotification would find that the window controller already had no document when they received their notification.
• The NSWindowController would not get the NSWindowWillCloseNotification, and the document would not be closed, if the window controller had been the window's delegate and then the window's delegate was reset (because of the way -[NSWindow setDelegate:] deregisters the previous delegate as an observer of notifications).

In Mac OS 10.5 an NSWindow that has a window controller now sends it a private message when the window did (not will) close, fixing those and other problems. NSWindowControllers no longer register for or depend on receiving NSWindowWillCloseNotification.

Also, a change that's similar to one in -[NSWindowController dealloc] has been made, and the window controller itself is now released instead of autoreleased (to balance a [self retain] that the window controller does before sending -removeWindowController:self to its document). For backward binary compatibility the new behavior is only done in applications linked against Mac OS 10.5 or later.

Bug Fixes in -[NSWindowController dealloc]

-[NSWindowController setWindow:] makes the window control the next responder of the window, which is as designed. However, this could result in the NSWindow messaging the NSWindowController's zombie, depending on which object was deallocated first. In Mac OS 10.5, -[NSWindowController dealloc] fixes this problem by sending the window -setNextResponder:nil if the window controller has a window and is its next responder.

In previous versions of Mac OS X, -[NSWindowController dealloc] autoreleased the window and the top level objects from the nib it loaded. This made it needlessly difficult to debug programming mistakes in applications. In Mac OS 10.5 -[NSWindowController dealloc] now releases the window and top level objects instead. For backward binary compatibility the new behavior is only done in applications linked against Mac OS 10.5 or later.

Advice for People Setting up Nibs that Have NSWindowController File's Owners

NSWindowController has never depended on being the controlled window's delegate to do its job. NSWindowController doesn't even implement any NSWindow delegate methods. A subclass of NSWindowController is a fine place to put implementations of NSWindow delegate methods, and if you do so you'll probably need to connect the delegate outlet of a window in a nib to the nib file's owner, an instance of your NSWindowController subclass, but you do not have to do so on NSWindowController's account.

New Behavior for NSWindowController Frame Autosave Names

In previous versions of Mac OS X, -[NSWindowController setWindow:], which is typically invoked at nib-loading time, always set the frame autosave name of the window to the window controller's own frame autosave name. This was a significant inconvenience because it meant that the name you set in the window using Interface Builder was always effectively ignored. In Mac OS 10.5 -[NSWindowController setWindow:] now only sets the window's frame autosave name if its own is something other than nil or the empty string. This means that a window's frame autosave name is now useful even when the window is loaded by a window controller. You can still explicitly invoke -[NSWindowController setWindowFrameAutosaveName:] if for some reason you need to override the window's frame autosave name at runtime. For backward binary compatibility the new behavior is only done in applications linked against Mac OS 10.5 or later.


NSSplitView Enhancements

Several enhancements have been made to NSSplitView in Mac OS 10.5. For detailed information on all of the methods mentioned here, see the comments in <AppKit/NSSplitView.h>.

So that you can programmatically set the position of a divider to an arbitrary position, a new -setPosition:ofDividerAtIndex: method has been added.

So that you can programmatically query the range of useful values that can be passed to -setPosition:ofDividerAtIndex:, or implement relatively complex behaviors in split view delegate methods, new -minPossiblePositionOfDividerAtIndex: and -maxPossiblePositionOfDividerAtIndex: methods have been added.

You can programmatically collapse a subview by invoking -minPossiblePositionOfDividerAtIndex: or -maxPossiblePositionOfDividerAtIndex: and passing the result to -setPosition:ofDividerAtIndex:.

To make it easier for you to let the user collapse subviews by double-clicking on dividers, a new -splitView:shouldCollapseSubview:forDoubleClickOnDividerAtIndex: delegate method has been added.

Autosaving of divider positions and subview collapsing has been added to NSSplitView. It's controlled by the new -setAutosaveName: and -autosaveName: methods.

NSSplitView now puts an NSSplitViewDividerIndex entry in the user info dictionaries of NSSplitViewWillResizeSubviewsNotification and NSSplitViewDidResizeSubviewsNotification notifications it sends, and passes to the delegate's -splitViewWillResizeSubviews: and -splitViewDidResizeSubviews: methods, when the user is dragging a divider, or has double-clicked on a divider to collapse a subview, or when -setPosition:ofDividerAtIndex: is being invoked.

So that you can easily configure split views with thin dividers, NSSplitView now has -setDividerStyle: and -dividerStyle methods. The two possible styles are NSSplitViewDividerStyleThick and NSSplitViewDividerStyleThin. The default is thick.

In case NSSplitView's default divider color does not look good in in the context of your application's UI, NSSplitView now has a -dividerColor method. It's invoked by -[NSSplitView drawDividerInRect:], and returns a value based on the split view's style. You can override it to customize.

Note: -[NSSplitView dividerColor] has changed since the WWDC 2007 seed. It now returns [NSColor clearColor] instead of [[self window] backgroundColor] for the thick divider style. Also, for backward binary compatibility it behaves differently in apps linked against Mac OS 10.4 or earlier. In those older apps it returns [[self window] backgroundColor] if [self isOpaque] returns YES, nil otherwise. -[NSSplitView isOpaque] has also changed since the WWDC 2007 seed. In apps linked against Mac OS 10.5 or newer it returns YES if the divider color is opaque and (because NSSplitViews don't draw backgrounds, but do adjust their subviews to cover everything but the dividers) all of the subviews are opaque. In apps linked against Mac OS 10.4 or older it returns YES if all of the subviews are opaque and [self dividerThickness] returns the same value NSSplitView's default implementation of -dividerThickness would return and [self isPaneSplitter] returns YES.

Thin dividers would be hard to drag if the user had to precisely click on them them. To give the user a bigger area to click on, the "effective" area of thin dividers is larger than the drawn area, by two points in either direction, in Mac OS 10.5. So that you can customize this behavior, when stealing mouse clicks away from adjacent controls is not appropriate for example, there is a new -splitView:effectiveRect:forDrawnRect:ofDividerAtIndex: delegate method you can implement.

Also, you can put a divider "handle" in your UI to give the user another way to drag the divider. So that you can point a split view to the handle's area and let it manage divider dragging (and the mouse cursor too), there is a new -splitView:additionalEffectiveRectOfDividerAtIndex: delegate method you can implement.

A common UI pattern now is to provide a button to show and hide one subview or another of a split view, and completely hide the divider when the subview between it and the edge of the window is hidden. To make it easy for you to do this there is a new -splitView:shouldHideDividerAtIndex: delegate method you can implement.

Bug Fixes in NSSplitView

In Mac OS 10.5 some longstanding bugs have been fixed in NSSplitView.

-[NSSplitView adjustSubviews] now does a much better job of not letting rounding errors accumulate when it is invoked repeatedly during window resizing. This fixes a wide variety of problems involving drifting, disappearing, and reappearing subviews.

NSSplitView now uses -[NSView setHidden:] when collapsing and uncollapsing a subview instead of setting the origin of the subview's frame somewhere far, far way. One result is that controls inside collapsed subviews can no longer hold onto the key focus, and can therefore no longer interfere with a window's tabbing behavior.

Accessibility: because of NSSplitView's use of -[NSView setHidden:], collapsed subviews are automatically no longer present in the accessibility hierarchy.

-[NSSplitView adjustSubviews] now reliably apportions space to uncollapsed subviews even when their total width (in vertical split views) or height (horizontal) is zero when it is invoked.

During divider dragging NSSplitView now more reliably heeds the value returned by the delegate's -splitView:constrainMaxCoordinate:ofSubviewAt: method to prevent the user from making the collapsible subview below (in a horizontal split view) or to the right of (vertical) the divider smaller than a minimum size before it is collapsed. NSSplitView also now collapses and uncollapses adjacent subviews simultaneously as the user drags the divider, when there isn't room to show both of them uncollapsed, and both are collapsible.

NSSplitView now uses NSCursor's +resizeLeftCursor and +resizeRightCursor when appropriate, instead of just using +resizeLeftRightCursor all of the time. The same goes for +resizeUpCursor and +resizeDownCursor instead of +resizeUpDownCursor.

Advice for Programming with NSSplitView

If your application needs to know when a subview is collapsed or expanded, register for the NSSplitViewDidResizeSubviewsNotification, or implement the -splitViewDidResizeSubviews: delegate method, and use -[NSSplitView isSubviewCollapsed:]. Don't, for example, assume that a view will be collapsed soon after the delegate returned YES when sent -splitView:canCollapseSubview:.


NSWindow

We added API to specify that a window can become visible before login. Windows that need to be shown as part of login UI should have this property set. The default setting is NO.
- (BOOL)canBecomeVisibleWithoutLogin;
- (void)setCanBecomeVisibleWithoutLogin:(BOOL)flag;
We have added API to control sharing of the window content. -setSharingType: specifies whether the window content can be read and/or written from another process. The default sharing type is NSWindowSharingReadOnly, which means other processes can read the window content (eg. for window capture) but cannot modify it. If you set your window sharing type to NSWindowSharingNone, so that the content cannot be captured, your window will also not be able to participate in a number of system services, so this setting should be used with caution. If you set your window sharing type to NSWindowSharingReadWrite, other processes can both read and modify the window content.
enum {
    NSWindowSharingNone = 0, // Window contents may not be read by another process
    NSWindowSharingReadOnly = 1, // Window contents may be read but not modified by another process
    NSWindowSharingReadWrite = 2 // Window contents may be read or modified by another process
};
typedef NSUInteger NSWindowSharingType;
- (void)setSharingType:(NSWindowSharingType)type;
- (NSWindowSharingType)sharingType;
We have also added -setPreferredBackingLocation: to set the preferred location for the window backing store. In general, you should not use this API unless indicated by performance measurement. The default preferred location is NSWindowBackingLocationDefault, which means that the system determines whether window backing store is kept in VRAM or main memory. You can use this API to set a preferred location for your window backing store, but the system may choose a different location. You can use -backingLocation to find the current location of your window backing store.
enum {
    NSWindowBackingLocationDefault = 0,        // System determines if window backing store is in VRAM or main memory
    NSWindowBackingLocationVideoMemory = 1,        // Window backing store is in VRAM
    NSWindowBackingLocationMainMemory = 2        // Window backing store is in main memory
};
typedef NSUInteger NSWindowBackingLocation;
- (void)setPreferredBackingLocation:(NSWindowBackingLocation)backingLocation;
- (NSWindowBackingLocation)preferredBackingLocation;
- (NSWindowBackingLocation)backingLocation;
We have also added API to make it easier to customize the behavior of the document icon in a window title bar. Prior to Leopard, you could call -[NSWindow setTitleWithRepresentedFilename:] or -[NSWindow setRepresentedFilename:] to indicate that a window represents a file at the given path. This causes two behaviors: The window shows a document icon appropriate for the given file path. This icon is draggable, and creates an alias, copy, or generic representation of the file when dropped. Secondly, the document icon and the title form a cmd-clickable region. A cmd-click in this region shows a popup menu. Selecting an item from this menu causes it to be shown in Finder.

In Leopard, we have added API to allow a document icon for any window, given a URL. If you call setRepresentedURL: with a valid non-nil URL, the window will show a document icon in the titlebar. If the url represents a filename or other resource with a known icon, that icon will be used as the document icon. Otherwise the default document icon will be used. The icon can be customized using [[NSWindow standardWindowButton:NSWindowDocumentIconButton] setImage:customImage]. If the URL is not nil and its path is not empty, the window will have a pop-up menu which can be shown via command-click on the area containing the document icon and title. By default, this menu will display the path components of the URL. The presence and contents of this menu can be controlled by the delegate method window:shouldPopUpDocumentPathMenu:. If the URL is nil or has an empty path, the window will not show a document icon and will not have a pop-up menu available via command-click.
- (void)setRepresentedURL:(NSURL *)url;
- (NSURL *)representedURL;
If a window has a representedURL, the window will by default show a path popup menu for a command-click on a rectangle containing the window document icon button and the window title. The window delegate may implement -window:shouldPopupDocumentPathMenu: to override NSWindow's default behavior for path popup menu. A return of NO will prevent the menu from being shown. A return of YES will cause the window to show the menu passed to this method, which by default will contain a menuItem for each path component of the representedURL. If the representedURL has no path components, the menu will have no menu items. Before returning YES, the window delegate may customize the menu by changing the menuItems. menuItems may be added or deleted, and each menuItem title, action, or target may be modified.
- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu;
The window delegate may implement -window:shouldDragDocumentWithEvent:from:withPasteboard: to override NSWindow document icon's default drag behavior. The delegate can prohibit the drag by returning NO. Before returning NO, the delegate may implement its own dragging behavior using -[NSWindow dragImage:at:offset:event:pasteboard:source:slideBack:]. Alternatively, the delegate can enable a drag by returning YES, for example to override NSWindow's default behavior of prohibiting the drag of an edited document. Lastly, the delegate can customize the pasteboard contents before returning YES.
- (BOOL)window:(NSWindow *)window
shouldDragDocumentWithEvent:(NSEvent *)event
from:(NSPoint)dragImageLocation
withPasteboard:(NSPasteboard *)pasteboard;
NSWindow now has a method to get a dock tile instance, which allows you to control some aspects of the dock tile corresponding to the miniaturized window. For further discussion, see the NSDockTile section.
- (NSDockTile *)dockTile;
-[NSWindow center] now uses a different algorithm to position windows. The effect of this change is that a window whose height is close to or greater than 2/3 of the visible screen height will now be positioned vertically in a way that is consistent with smaller windows.

The action of the standard toolbar button now goes through the public toggleToolbarShown: method, passing the toolbar button as the sender.

Support has been added for a Heads Up Display (HUD) window style. A HUD window can be created using NSHUDWindowMask. The window must be an NSPanel or subclass. NSHUDWindowMask may be combined with other window styles to create a borderless or titled window with a certain appearance and behavior. Both the titled and borderless window float above other windows and are partially transparent. They hide-on-deactivate, which means a HUD window will only be visible when its owning app is active. The following combinations are valid:
NSHUDWindowMask
    | NSBorderlessWindowMask - borderless window with HUD transparency and window level
or
    | NSTitledWindowMask | NSUtilityWindowMask - titled window with HUD transparency and window level
        and any of the following:
        | NSClosableWindowMask - titled window with HUD close box, transparency, and window level
        | NSResizableWindowMask - titled window with HUD resize corner, transparency, and window level
        | NSNonactivatingPanelMask - no effect on appearance, but owning app will not necessarily be active when this window is the key window

the following are not valid

    NSMiniaturizableWindowMask - not supported
    NSTexturedBackgroundWindowMask - not supported
    NSDocModalWindowMask - not supported
    NSUnifiedTitleAndToolbarWindowMask - not supported

A secondary click in the title bar of a window now shows the context menu of the toolbar, if any. Likewise, a double-click in the toolbar background of such a window will minimize the window if minimize on double-click is enabled. Because there is no visual separation between the title bar and the toolbar, they are now treated more as if they were one area. A secondary click in the document icon or title bar of a window with a represented URL will now show the document pop up, just as a command click does.

We have modified the window appearance. The window titlebar and toolbar background are drawn with a dark gradient when key or main, and a lighter gradient when inactive. The NSUnifiedTitleAndToolbarWindowMask styleMask no longer has any effect, since all windows with toolbars now have a unified look. Windows whose styleMask includes NSTexturedBackgroundWindowMask have a window background which also darkens when key or main and lightens when inactive, and may have a second gradient in the section below the window content. Windows whose styleMask does not include NSTexturedBackgroundWindowMask have a window background which is a solid fill and does not change when key, main, or inactive.

We have modified the look of main and utility windows. A window that is main and not key now has the same title bar color as a key window, but inactive window buttons. A utility window that is not key now has an inactive title bar buttons. With this change, active title bar buttons now have a more consistent correlation with the key window state.

In Leopard, textured windows have a gradient on the top and bottom section of the window where metal was previously visible.

In many cases, we can detect the appropriate area for a textured window gradient using an algorithm based on opaque views, but in some cases we cannot, since a view may declare itself opaque then draw the window background, for example. For application windows where the window background detection doesn't work, we have provided API. We hope that most windows will look correct without invoking this API.

If the automatic calculation of window gradient does not yield the correct results, the automatic calculation can be disabled with -setAutorecalculatesContentBorderThickness:NO. If this method is called without also setting a content border thickness for a given edge, the content border thickness on that edge will be 0. A content border thickness can be set by calling -setContentBorderThickness:forEdge:. Alternatively, a window subclass can override -contentBorderThicknessForEdge:. If -setContentBorderThickness:forEdge: is called other than by NSWindow's automatic calculation, and autorecalculatesContentBorderThicknessForEdge: returns YES for the given edge, the behavior is undefined. (That is, NSWindow is likely to overwrite the custom value).

Non-textured windows can also now be told to draw the window background gradient in a border on the bottom of the window. By default, non-textured windows have no bottom border.

-setContentBorderThickness:forEdge: and contentBorderThicknessForEdge: use the coordinate system of the window content, so they are in points rather than pixels. Note that the contentBorder does not include the titlebar or toolbar, so a window that just wants the gradient in the titlebar and toolbar will have a contentBorderThickness of 0 for NSMaxYEdge.

Calling -setContentBorderThickness:forEdge:NSMinXEdge/NSMaxXEdge will raise an exception. Likewise calling -setAutorecalculatesContentBorderThickness:NO forEdge:NSMinXEdge/NSMaxXEdge will raise an exception. In a non-textured window only, calling -setContentBorderThickness:forEdge:NSMaxYEdge will raise an exception, as will calling -setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge. It is only valid to set the content border thickness of the top edge in a textured window.

The behavior of -setContentBorderThickness:forEdge:NSMinYEdge and -setAutorecalculatesContentBorderThickness:NO forEdge:NSMinYEdge for non-textured windows will do the following: The top gradient will be repeated in the bottom border, separator lines will be drawn between the content and the bottom border, and the bottom corner will be rounded. Other methods on non-textured windows or unused edges will return 0.0 or YES.

- (void)setContentBorderThickness:(CGFloat)thickness forEdge:(NSRectEdge)edge;
- (CGFloat)contentBorderThicknessForEdge:(NSRectEdge)edge;

- (void)setAutorecalculatesContentBorderThickness:(BOOL)flag forEdge:(NSRectEdge)edge;
- (BOOL)autorecalculatesContentBorderThicknessForEdge:(NSRectEdge)edge;

We deprecated an API added earlier in Leopard for Spaces and replaced it with a more general form. Windows have different behavior under Spaces based on this API.

NSWindowCollectionBehaviorDefault windows can be either document or floating. Document windows are associated with one space at a time. If you order a normal window onscreen, it becomes associated with the current space. If you then switch spaces, the window does not show up in the new space. If you switch focus back to the window which is onscreen in another space, you get switched to the space containing the window. A TextEdit document window is an example of a document window. Floating windows are also almost space independent, except that they are associated with their owning app. If you order a floating window onscreen, it orders onscreen in the current space. If you switch spaces, the floating window shows up in the new space if and only if the owning app is active. The floating window itself is not counted as a window that can cause the app to be chosen as active on a space switch. Note that floating windows are usually, but not required to be, hide on deactivate. AppKit automatically sets windows whose window-level is non-0 to floating. The TextEdit font panel is an example of a floating window.

NSWindowCollectionBehaviorCanJoinAllSpaces windows can be thought of as space independent. If you order an all-space window onscreen, it orders onscreen in the current space. If you then switch spaces, the all-space window shows up in the new space. If you switch focus to the all-space window, you stay in the current space. The menu bar is an example of this kind of window.

NSWindowCollectionBehaviorMoveToActiveSpace windows are visible on only one space at a time, but move to the active space when needed. If you order a MoveToActiveSpace window onscreen, it becomes associated with the active space (which is the current space). If you then switch spaces, the window does not show up in the new space. If you switch focus back to the MoveToActiveSpace window, it becomes visible in the active space, rather than causing a space switch like a normal window would. The AppKit find panel is an example of a this kind of window.
enum {
NSWindowCollectionBehaviorDefault = 0,
NSWindowCollectionBehaviorCanJoinAllSpaces = 1 << 0,
NSWindowCollectionBehaviorMoveToActiveSpace = 1 << 1
};
typedef NSUInteger NSWindowCollectionBehavior;
- (void)setCollectionBehavior:(NSWindowCollectionBehavior)behavior;
- (NSWindowCollectionBehavior)collectionBehavior;
The setCanBeVisibleOnAllSpaces/canBeVisibleOnAllSpaces API, introduced earlier in Leopard, is deprecated in favor of setCollectionBehavior:/collectionBehavior
-(void)setCanBeVisibleOnAllSpaces:(BOOL)flag    AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED;
-(BOOL)canBeVisibleOnAllSpaces AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED;
NSBackingStoreRetained is no longer supported as a backing store type. Windows created with a backing store type of NSBackingStoreRetained will be silently promoted to NSBackingStoreBuffered. In the MacOSX implementation, NSBackingStoreRetained doesn't have any advantages in behavior or performance over NSBackingStoreBuffered, and on some hardware may behave significantly worse due to performance of display frame buffer access.

Sheets

Since the September 2007 seed of 10.5 we have introduced a new sheet effect for standard windows.  Sheets are now attached under the content border, which includes the titlebar, toolbar, and any additional content border thickness on the top edge.  There is no longer any "slot" at the attachment point between the sheet and the window.  Instead, there is a shadow on the top edge of the sheet where it connects to the window.  If there is no toolbar or content border aside from the titlebar, the sheet is positioned below the titlebar.

Due to compatibility concerns, the additional content border thickness is only taken into account for positioning the sheet if it has been set explicitly.  That is, if the window returns YES from [self autorecalculatesContentBorderThicknessForEdge:NSMaxYEdge], the auto-calculated content border thickness is not included when positioning the sheet.

NSScreen

In order to return the correct screen frame information after a programmatic display configuration change, NSScreen no longer caches screen frame information. Instead, it retrieves the requested information from Quartz. This has implications for applications which may have worked around the previous NSScreen behavior where a stale screen frame could be returned after a display configuration change.


NSAlert

We have added support to NSAlert for a suppression checkbox and an accessory view. setShowsSuppressionButton: indicates whether or not the alert should contain a suppression checkbox. The default is NO. This checkbox is typically used to give the user an option to not show this alert again. If shown, the suppression button will have a default localized title similar to @"Do not show this message again." You can customize this title using [[alert suppressionButton] setTitle:]. When the alert is dismissed, you can get the state of the suppression button, using [[alert suppressionButton] state] and store the result in user defaults, for example. This setting can then be checked before showing the alert again. By default, the suppression button is positioned below the informative text, and above the accessory view (if any) and the alert buttons, and left-aligned with the informative text. However do not count on the placement of this button, since it might be moved if the alert panel user interface is changed in the future. If you need a checkbox for purposes other than suppression text, it is recommended you create your own using an accessory view.
- (void)setShowsSuppressionButton:(BOOL)flag;
- (BOOL)showsSuppressionButton;
suppressionButton returns a suppression button which may be customized, including the title and the initial state. You can also use this method to get the state of the button after the alert is dismissed, which may be stored in user defaults and checked before showing the alert again. In order to show the suppression button in the alert panel, you must call -setShowsSuppressionButton:YES.
- (NSButton *)suppressionButton;

setAccessoryView: sets the accessory view displayed in the alert panel. By default, the accessory view is positioned below the informative text and the suppression button (if any) and above the alert buttons, left-aligned with the informative text. If you want to customize the location of the accessory view, you must first call -layout. See the discussion of -layout for more information.
- (void)setAccessoryView:(NSView *)view;
- (NSView *)accessoryView;
The following method can be used to indicate that the alert panel should do immediate layout, overriding the default behavior of laying out lazily just before showing the panel. You should only call this method if you want to do your own custom layout after it returns. You should call this method only after you have finished with NSAlert customization, including setting message and informative text, and adding buttons and an accessory view if needed. You can make layout changes after this method returns, in particular to adjust the frame of an accessory view. Note that the standard layout of the alert may change in the future, so layout customization should be done with caution.
- (void)layout;

[alert setIcon:nil] now restores the application icon, as documented. Prior to this change, [alert setIcon:nil] would actually remove the icon from the alert.


If alertWithError: is called with a nil NSError, it will now return an alert that displays a generic error message rather than an empty and confusing panel. Under normal circumstances a nil argument to such a method should be considered a programming error and should result in an exception. However, since runtime errors that this method is supposed to help with are not always encountered during testing, and since the problem is already occurring in the context of a user level error that the user should know about, displaying the alert remains a reasonable approach. Clearly the problem should be fixed by finding and fixing the subsystem that is failing to properly create an NSError.


NSDockTile

We have added a new class, NSDockTile, which can be used to customize the dock tile behavior for both NSApplication and NSWindow.

An NSDockTile has a size, which corresponds to the size of the backing store in the dock, which may be bigger than the current tile size, and is defined by the current user space scale factor. Currently, it is 128x128 on a system with user space scale factor 1.0, but you should not make any assumptions about this size remaining the same in the future.

You can add a contentView to the dock tile. If you want to draw into the dock tile, you have to tell the dock tile to display, and you have to draw the whole tile. Certain system activity will also cause the dock tile to resize and/or display. Any badging will be applied after the dock tile displays.

You can badge the dock tile with a localized string representing a count. You can also specify whether or not the tile should show the application badge.

Existing API for dock tile management (setting app icon, dock tile menu, miniwindow icon, and miniwindow title) will not be replaced with dock tile API at this point. A future direction could be to move all dock tile management to NSDockTile.
@interface NSDockTile : NSObject
- (NSSize)size;
- (void)setContentView:(NSView *)view;
- (NSView *)contentView;
- (void)display;
- (void)setShowsApplicationBadge:(BOOL)flag;
- (BOOL)showsApplicationBadge;
- (void)setBadgeLabel:(NSString *)string;
- (NSString *)badgeLabel;
- (id)owner;
@end
Please refer to <AppKit/NSDockTile.h> and the documentation for further details on NSDockTile.


NSApplication

Like NSWindow, NSApplication now has a method to get a dock tile instance. It allows you to control some aspects of the dock tile corresponding to the application. For further discussion, see the NSDockTile section right above.
- (NSDockTile *)dockTile;
For applications built on Leopard or later, the dock tile icon is now restored to its default state when the application terminates, meaning badge labels and such are removed automatically.  Some applications previously accomplished this by calling RestoreApplicationDockTileImage.  This is incompatible with NSDockTile on Leopard, so you should modify your application if you are doing this.  If you need to restore the dock tile icon on Tiger in a Leopard compatible way, you can do so by calling -[NSApp setApplicationIconImage:nil].


Tracking areas

We created a new model for mouse tracking and cursor updates. An NSTrackingArea will encapsulate the information used to create trackingRects today, including a rect (relative to view bounds), an owner (which will receive events generated on behalf of the trackingArea), a userInfo dictionary, and options as described below. Note that NSTrackingArea conforms to NSCoding and NSCopying.

An NSTrackingArea can be used like a traditional trackingRect, which will generate mouseEntered and mouseExited events as the mouse moves in and out of the area. It can also be used for cursorUpdates, which will be sent to the view under the mouse when the mouse moves in or out of the area. Lastly, it can be used to register for mouseMoved events for all mouse movement inside of the area. These options can be combined with bit-wise or to install a single NSTrackingArea that provides all three options.

You can get the NSTrackingArea that generated a mouseEntered or mouseExited event using -[event trackingArea].

An NSTrackingArea can be active only when its view is the firstResponder, or when the view is in the key window, or when the view is in any window in the active app, or always. Some of these options do not work with some of the types. For example, you cannot request cursorUpdates in an inactive app.

As with traditional trackingRects, you can specify whether you want to assume that the mouse is inside or outside of the trackingArea. Additionally, a trackingArea can be set up to stay in sync with the visibleRect of the view, which then makes one of the most common situations trivial. Lastly, you can request mouseEntered and mouseExited events to be generated while the mouse button is down (that is, during mouse dragging).
@interface NSTrackingArea : NSObject <NSCopying, NSCoding>
- (NSTrackingArea *)initWithRect:(NSRect)rect
options:(NSTrackingAreaOptions)options
owner:(id)owner
userInfo:(NSDictionary *)userInfo;
- (NSRect)rect;
- (NSTrackingAreaOptions)options;
- (id)owner;
- (NSDictionary *)userInfo;
@end
Please refer to <AppKit/NSTrackingArea.h> and the documentation for further details on NSTrackingArea.

The following API has been added to NSView:
- (void)addTrackingArea:(NSTrackingArea *)trackingArea;
A view or other object creates an NSTrackingArea, then adds it to a view using this API. Not meant to be overridden.
- (void)removeTrackingArea:(NSTrackingArea *)trackingArea;
This API is used to remove a trackingArea from a view. Not meant to be overridden.
- (NSArray *)trackingAreas;
Get the list of trackingAreas that have been added to the view. Not meant to be overridden.
- (void)updateTrackingAreas;
This will be sent to a view when something has changed which is likely to require recomputation of trackingAreas, for example a change in the size of the visibleRect. Moving a view into or out of a window will not cause this message to be sent, except that it will be sent once when the view is first created and added to a window. Should be overridden by a view to remove and add its tracking areas, and should call super.

The third part of the API improves cursor arbitration by adding a responder method, -cursorUpdate:. When an NSCursorUpdate event is received for a window, it gets routed to the view under the mouse, using normal hitTesting. The view under the mouse receives the cursorUpdate: message. This behaves like other event responder methods - if the view doesn't implement cursorUpdate:, the NSResponder implementation will send it to the nextResponder. If the view implements cursorUpdate: but decides not to handle the particular event, it should invoke super.

The following API has been added to NSResponder:
- (void)cursorUpdate:(NSEvent *)event;
Override to set cursor. Default implementation uses cursorRect if cursorRects are valid. If no cursorRect calls super, to send up responder chain.

The following API has been added to NSEvent, and is valid for NSMouseEntered and NSMouseExited events. Note that it is not valid for NSMouseMoved events.
- (NSTrackingArea *)trackingArea;
-trackingArea can be sent to an NSMouseEntered, NSMouseExited, or NSCursorUpdate event. It is not valid for an NSMouseMoved event. If the event was generated by an old-style trackingRect, -trackingArea will return nil.


We fixed a bug in the interpretation of the assumeInside flag for tracking rects added via -[NSView addTrackingRect:owener:userData:assumeInside:]. On Tiger and previous, passing YES for the assumeInside flag yielded inconsistent results. If the mouse was initially outside the tracking rect when the tracking rect was added, no event was generated, and a mouseEntered event was sometimes generated when the mouse entered the tracking rect through a subsequent mouseMoved. On Leopard, passing YES for the assumeInside flag will cause a mouseExited event to be generated if the mouse is initially outside the tracking rect. A mouseEntered will be generated when the mouse enters the tracking rect if it was initially outside. If this new behavior causes a problem for your application, you can get the Tiger behavior by setting the NSTigerBehaviorForTrackingRects user default to YES.


NSEvent

We added methods to convert between an NSEvent and a Carbon EventRef. -eventRef is valid for all events and returns an EventRef corresponding to the NSEvent. The EventRef is retained by the NSEvent, so will be valid as long as the NSEvent is valid, and will be released when the NSEvent is freed. You can use RetainEvent to extend the lifetime of the EventRef, with a corresponding ReleaseEvent when you are done with it. If there is no EventRef corresponding to the NSEvent, -eventRef will return NULL. +eventWithEventRef: returns an autoreleased NSEvent corresponding to the EventRef. The EventRef is retained by the NSEvent and will be released when the NSEvent is freed. If there is no NSEvent corresponding to the EventRef, +eventWithEventRef: will return nil.
- (const void * /* EventRef */)eventRef;
+ (NSEvent *)eventWithEventRef:(const void * /* EventRef */)eventRef;
We also added methods to convert between an NSEvent and a CGEventRef. -CGEvent is valid for all events and returns an autoreleased CGEventRef corresponding to the NSEvent. If you want to control the lifetime of the CGEventRef, you should retain it. If there is no CGEventRef corresponding to the NSEvent, -CGEvent will return NULL. + eventWithCGEvent: returns an autoreleased NSEvent corresponding to the CGEventRef. If there is no NSEvent corresponding to the EventRef, +eventWithCGEvent: will return nil. Converting from an NSEvent to a CGEventRef can be lossy, and you should not attempt to use the key event handling facilities provided by CGEventRef.
- (CGEventRef)CGEvent;
+ (NSEvent *)eventWithCGEvent:(CGEventRef)cgEvent;
There is now a method to enable or disable mouse coalescing, and a method to query the current state. Mouse coalescing is on by default.
+ (void)setMouseCoalescingEnabled:(BOOL)flag;
+ (BOOL)isMouseCoalescingEnabled;
If you build your application on Leopard, and your application installs an event handler on the event monitor target using GetEventMonitorTarget, the monitored event will be sent to the event handler you installed rather than to -[NSApplication sendEvent:]. For applications built on Tiger or previous, the monitored event will be sent to sendEvent:. You can override this default behavior by setting NSDispatchMonitoredEvents. If NSDispatchMonitoredEvents is YES, the event will be sent to sendEvent:; if NO, it will be sent to the installed event handler.

NSScrollWheel events will now be sent to the window under the mouse, whether or not the window is active. In previous version of Mac OS X, NSScrollWheel events were only sent to the window under the mouse if the window had key focus, with the exception of utility windows which received NSScrollWheel events even when inactive.


Key equivalents

We fixed a problem where NSKeyUp events were sent to performKeyEquivalent: if the command-key was not down. This problem could cause a key equivalent to be performed twice if the receiver didn't check the event type for NSKeyDown. The fix applies only to applications built on Leopard or later, to preserve binary compatibility for any application which may have been dependent on the old behavior.

The modifier flags are now preserved in NSKeyDown <esc> events. Prior to this change, NSWindow would strip modifier flags from the <esc> key event before invoking -performKeyEquivalent:. We don't expect applications to be dependent on this behavior, but if you need to ignore modifier flags on <esc> keyDown events, you can override -performKeyEquivalent: to do so.

In -[NSWindow sendEvent:] we now send keyDown: to the first responder even if the command-key modifier is set. An NSKeyDown event will only reach this point if it was not recognized as a key equivalent. One effect of this change is to enable custom key binding entries with command-key modifiers. The change applies only to applications built on Leopard or later, to preserve binary compatibility for any application which may have been dependent on the old behavior.

NSApplication now sends a ctrl-key event to performKeyEquivalent: before sending the keyDown: event through the responder chain. This allows ctrl-key events to be used as menu key equivalents more reliably. Prior to this change, a ctrl-key event which had an emacs key binding would not be sent to performKeyEquivalent: if focus was in an NSTextView.


Dragging

-[NSDraggingInfo slideDraggedImageTo:] is now implemented to behave as documented. This change is enabled only for applications built on Leopard or later to avoid changing behavior of older binaries in ways that may be incorrect.

-draggingEnded is now implemented for applications linked on Leopard or later.


NSDatePicker

NSDatePicker - Range mode

NSDatePicker now implements the existing date range selection API for the mini-calendar style date picker. This is enabled by calling setDatePickerMode: and passing in NSRangeDateMode. The range is represented by a start date (NSDate; accessible through dateValue) and a time interval (NSTimeInterval; accessible through timeInterval). If the date picker is a textfield style date picker, setDatePickerMode: is ineffectual and timeInterval returns 0.0 as before. If the date picker is in NSSingleDateMode, then timeInterval always returns 0.0.

Date ranges can be selected in the mini-calendar interface by clicking and dragging across calendar days or by shift-clicking. The calendar's months will also advance or retreat as the mouse is dragged below or above the area where calendar days are displayed.

NSDatePicker - Small and mini sizes

The text field styles of NSDatePicker now support small and mini control sizes through the -setControlSize: method. However, this only affects the size of the internal stepper cell. The size of the text field is determined by the size of its font and number of displayed date components.

NSDatePicker - Text field only style

NSDatePicker now supports a third style: NSTextFieldDatePickerStyle. This is identical to NSTextFieldAndStepperDatePickerStyle in every way, except it does not display a stepper.

NSDatePickerCell - Creation performance

The NSDatePickerCell creation speed has been significantly improved by drastically reducing the number of NSDateFormatters created internally.

NSDatePicker - Date Arithmetic Improvements

NSDatePickerCell's date arithmetic implementation has changed substantially in Leopard, abandoning use of the obsolete NSCalendarDate class (which only supports the Gregorian calendar, and yields imprecise results for dates in the distant past -- e.g. for years circa 1500) in favor of a fully modern NSCalendar-based implementation underpinned by ICU library routines. This fixes significant editing issues for Gregorian calendar dates, while providing substantial localization improvements for non-Gregorian calendars.


Text

New Text Document Formats

The text system now has support for reading and writing both the OASIS Open Document text document format and the ECMA Office Open XML text document format. AppKit/NSAttributedString.h has two new constants for this, NSOfficeOpenXMLTextDocumentType and NSOpenDocumentTextDocumentType. The /usr/bin/textutil command has been updated to support both formats.

NSAttributedString HTML Import

Since Tiger, NSAttributedString has used WebKit for all import of HTML documents (but not for export). Since WebKit document loading is not threadsafe, this has not been safe to use on background threads. For applications linked on Leopard and later, if NSAttributedString is used to import HTML documents on a secondary thread, the usage of WebKit will be transferred to the main thread via performSelectorOnMainThread:withObject:waitUntilDone:. This makes such usage threadsafe, but it requires that the main thread be running the run loop in one of the common modes. This behavior can be overridden by setting the default NSRunWebKitOnAppKitThread to either YES (to obtain the new behavior regardless of linkage) or NO (to obtain the old behavior regardless of linkage).

In versions prior to Leopard, NSAttributedString HTML import would set the NSBackgroundColorDocumentAttribute to [NSColor whiteColor] in cases in which the HTML did not specify a background color. This will continue to be true for applications linked on system versions prior to Leopard, but on Leopard and later, for applications linked on Leopard and later, no NSBackgroundColorDocumentAttribute will be set in these cases.

NSMutableAttributedString Note

The method -[NSMutableAttributedString readFromURL:options:documentAttributes:error:] is expected to replace the text of the receiver with the contents of the desired file. (The documentation states: "Sets the contents of receiver from the file at url.")

It works as expected for plaintext formatted files. However, for RTF formatted files, the contents of the file are appended to the previous string instead of replacing the previous string. This inconsistency is a bug; when using this method with existing content it's best to clear the content away explicitly.

NSTextStorage Scripting

For applications linked on Leopard or later, we now check for nil font in scripting calls and treat it as Helvetica 12. This impacts the calls font, fontName, fontSize, setFontName:, and setFontSize:.


Non-Contiguous Layout

NSLayoutManager now has a new option, referred to as non-contiguous layout. Previously, both glyph generation and layout have always been performed in order from the beginning to the end of the document. When non-contiguous layout is turned on, however, the layout manager gains the option of performing glyph generation or layout for one portion of the document without having done so for previous sections. This can provide significant performance improvements for large documents.

Non-contiguous layout is not turned on automatically because direct clients of NSLayoutManager typically have relied on the previous behavior--for example, by forcing layout for a given glyph range, and then assuming that previous glyphs would therefore be laid out. Clients who use NSLayoutManager only indirectly--for example, those who use NSTextView without directly calling the underlying layout manager--can usually turn on non-contiguous layout without difficulty. Clients using NSLayoutManager directly will need to examine their usage before turning on non-contiguous layout.

The methods directly concerned with non-contiguous layout are as follows:
- (void)setAllowsNonContiguousLayout:(BOOL)flag;
- (BOOL)allowsNonContiguousLayout;
- (BOOL)hasNonContiguousLayout;
The first allows non-contiguous layout to be turned on and off, and the second examines the state of that setting. Note that turning the flag on allows but does not require the layout manager to use non-contiguous layout, and it may in fact choose not to do so depending on the configuration of the layout manager. In addition, there may be times at which there is no non-contiguous layout, such as when layout is complete; the third method allows the layout manager to report that to clients.

In addition, there are a number of new methods that are especially useful when working with non-contiguous layout. Previously, glyph generation and layout have been implicit side effects of calls that require that information. That is still the case, but with the possibility of non-contiguous layout it is not always obvious what portion of the document will be affected. The new methods allow this to be specified explicitly, although the layout manager reserves the right to generate glyphs or perform layout for a larger portion of the document as appropriate. In particular, if non-contiguous layout is not in use, then the range affected will always be extended back to the beginning of the document.
- (void)ensureGlyphsForCharacterRange:(NSRange)charRange;
- (void)ensureGlyphsForGlyphRange:(NSRange)glyphRange;
- (void)ensureLayoutForCharacterRange:(NSRange)charRange;
- (void)ensureLayoutForGlyphRange:(NSRange)glyphRange;
- (void)ensureLayoutForTextContainer:(NSTextContainer *)container;
- (void)ensureLayoutForBoundingRect:(NSRect)bounds inTextContainer:(NSTextContainer *)container;

New NSLayoutManager Implementation

Large portions of NSLayoutManager have been updated to use a new implementation that supports the new non-contiguous layout feature. However, independent of whether non-contiguous layout is in use, the new implementation also rationalizes and clarifies a number of other aspects of the layout manager API.

For example, setCharacterIndex:forGlyphAtIndex: nominally allows for an arbitrary mapping between glyph and character indexes. This has never actually been the case; there have always been implicit restrictions, in the sense that other NSLayoutManager functionality would fail in the presence of a nonsensical glyph-to-character mapping. Now, however, it is possible to state the restrictions and, eventually, enforce them by raising an exception when they are violated. The basic restriction is that the glyph stream may never be out of order with respect to the character stream. Multiple glyphs may map to a single character, or multiple characters to a single glyph, but all of the glyphs for a given character must follow all glyphs for preceding characters and precede all glyphs for following characters. Glyphs that would not otherwise have a character (such as hyphens) are assigned to the character for the nearest previous glyph that has characters, and characters that would not otherwise have glyphs are assigned to the glyph for the nearest previous character that has glyphs. The stock glyph generator and typesetter attempt to preserve a one-to-one character-to-glyph mapping, to the extent possible, by including padding NSNullGlyph entries; for example, if the characters 'f' and 'i' are represented by an 'fi' ligature, then the glyph stream would include an 'fi' ligature glyph followed by a null glyph so that there are two glyphs to match the two characters. However, this is neither guaranteed nor required in general.

The basic methods for examining the character-glyph mapping are characterIndexForGlyphAtIndex: and the new method
- (NSUInteger)glyphIndexForCharacterAtIndex:(NSUInteger)charIndex;
that now plays a symmetric role. Thus characterIndexForGlyphAtIndex: returns the index for the first character associated with the specified glyph, and glyphIndexForCharacterAtIndex: returns the index for the first glyph associated with the specified character. In neither case is there any special treatment for null glyphs. In the 'fi' ligature case, for example, if the null padding is used, then these methods would report an identity mapping between glyph and character indexes. Both methods also accept indexes beyond the last character or glyph; they return an index extrapolated from the last actual character or glyph index. Thus if there is an identity mapping between glyph and character indexes, then both characterIndexForGlyphAtIndex: and glyphIndexForCharacterAtIndex: will always return results numerically equal to their arguments.

The more complex methods glyphRangeForCharacterRange:actualCharacterRange: and characterRangeForGlyphRange:actualGlyphRange:, on the other hand, do take null glyphs into account. For example, to consider the 'fi' ligature case again, if glyphRangeForCharacterRange:actualCharacterRange: were to be called with a character range of length 1 covering either the 'f' or the 'i', the resulting glyph range would include both the 'fi' glyph and the null glyph, and the actual character range would include both the 'f' and the 'i' character. Likewise, if characterRangeForGlyphRange:actualGlyphRange: were to be called with a glyph range of length 1 covering either the 'fi' glyph or the null glyph, the resulting character range would include both the 'f' character and the 'i' character, and the actual glyph range would include both the 'fi' glyph and the null glyph.

Both methods also have special treatment for ranges of zero length. For example, in the 'fi' ligature case, if glyphRangeForCharacterRange:actualCharacterRange: were to be called with a character range of length 0 before the 'f', the result would be a zero-length glyph range before the 'fi' glyph. However, if if glyphRangeForCharacterRange:actualCharacterRange: were to be called with a character range of length 0 between the 'f' and the 'i', the result would be a zero-length glyph range after the null glyph, and the actual character range would be a zero-length range after the 'i' character. In general, a zero-length character range within a multi-character sequence maps to a zero-length glyph range after the last glyph associated with the sequence, with a zero-length actual character range after the last character of the sequence. The same description applies to characterRangeForGlyphRange:actualGlyphRange:, interchanging the role of character and glyph indexes.

In general, character and glyph indexes now play a symmetric role in the character-glyph mapping, and glyphRangeForCharacterRange:actualCharacterRange: and characterRangeForGlyphRange:actualGlyphRange: behave symmetrically to each other. Both glyphRangeForCharacterRange:actualCharacterRange: and characterRangeForGlyphRange:actualGlyphRange: also accept indexes beyond the the last character or glyph, but the results they return are truncated after the last character or glyph rather than being extrapolated. This is in line with their role in, for example, calculating ranges of selected characters or glyphs.

Another aspect of NSLayoutManager that has been clarified is invalidation. Previously there was a distinction between hard and soft layout invalidation; it was expected that any change to the text would cause hard invalidation of the region that actually changed, followed by soft invalidation of all subsequent portions of the document, since they might move due to the change. Usually this would happen automatically as a result of change messages sent by the text storage to the layout manager, but anyone needing to invoke layout invalidation manually would have needed to respect the distinction. In Leopard, however, that distinction is no longer required; hard layout invalidation is the only sort necessary, and the equivalent of soft invalidation is arranged automatically. As a result, a new method
- (void)invalidateLayoutForCharacterRange:(NSRange)charRange actualCharacterRange:(NSRangePointer)actualCharRange;
has been provided to supersede the existing invalidateLayoutForCharacterRange:isSoft:actualCharacterRange:, as the equivalent of the latter with the soft flag set to NO. For code intended to run on Leopard only, the new method can be used. For code intended to run on both Leopard and Tiger, the old method should be used as before, in two calls, first with the soft flag set to NO, for the range actually being changed, and subsequently with the soft flag set to YES, for the range following the portion changed, to the end of the document.

In addition, layout manager/typesetter communication has been clarified by adding a new NSLayoutManager method for the use of the typesetter, to allow it to specify explicitly when portions of the glyph stream depend on layout--for example, because they have had hyphens inserted. The typesetter calls
- (void)invalidateGlyphsOnLayoutInvalidationForGlyphRange:(NSRange)glyphRange;
to specify that a certain range of glyphs is layout-dependent, and therefore the glyphs should be invalidated the next time their layout is invalidated, so that they will be regenerated before being laid out again.

Also, a new bulk NSLayout Manager method has been added to allow the typesetter to set locations for many glyph ranges at once:
- (void)setLocations:(NSPointArray)locations
startingGlyphIndexes:(NSUInteger *)glyphIndexes
count:(NSUInteger)count
forGlyphRange:(NSRange)glyphRange;
All of the glyph indexes should lie within the specified glyph range, the first of them should be equal to glyphRange.location, and the remainder should increase monotonically. Each location will be set as the location for the range beginning at the corresponding glyph index, and continuing until the subsequent glyph index, or until the end of the glyph range for the last location. Thus this method is equivalent to calling setLocation:forStartOfGlyphRange: for a set of ranges covering all of the glyphs in glyphRange.

NSLayoutManager setShowsInvisibleCharacters:

-setShowsInvisibleCharacters: method is now functional and substitute whitespace characters with either LOZENGE U+25CA or FULL STOP U+002E depending on glyph availability of the rendering font.

Thread safety of NSLayoutManager

Generally speaking, a given layout manager (and associated objects) should not be used on more than one thread at a time. Most layout managers will be used on the main thread, since it is the main thread on which their text views are being displayed, and since background layout occurs on the main thread. If it is intended that a layout manager should be used on a background thread, first make sure that text views associated with that layout manager (if any) will not be displayed while the layout manager is being used on the background thread, and second, turn off background layout for that layout manager while it is being used on the background thread.

Miscellaneous New NSLayoutManager Methods

To go along with the existing defaultLineHeightForFont:, NSLayoutManager has publicized
- (CGFloat)defaultBaselineOffsetForFont:(NSFont *)theFont;
to allow clients to obtain the baseline offset appropriate for a particular font within a particular layout manager, given its typesetter behavior and other settings.

In addition, it has also publicized the methods
- (BOOL)usesFontLeading;
- (void)setUsesFontLeading:(BOOL)flag;
that control whether the layout manager will use leading as specified by the font. The default is YES, since in most cases this is appropriate, but there are some cases where it is not; for example, for UI text a fixed leading is often specified by UI layout guidelines. All three of these methods are available going back to Mac OS X 10.2.

Some additions have been made to the NSLayoutManager temporary attribute methods to parallel more of the NSAttributedString attribute methods.
- (id)temporaryAttribute:(NSString *)attrName atCharacterIndex:(NSUInteger)location effectiveRange:(NSRangePointer)range;
- (id)temporaryAttribute:(NSString *)attrName atCharacterIndex:(NSUInteger)location
longestEffectiveRange:(NSRangePointer)range inRange:(NSRange)rangeLimit;
- (NSDictionary *)temporaryAttributesAtCharacterIndex:(NSUInteger)location
longestEffectiveRange:(NSRangePointer)range inRange:(NSRange)rangeLimit;
- (void)addTemporaryAttribute:(NSString *)attrName value:(id)value forCharacterRange:(NSRange)charRange;
There is a new NSLayoutManager method to obtain insertion points in bulk for a given line fragment. Previously the rects used for the insertion point indicator were obtained by calling rectArrayForCharacterRange:withinSelectedCharacterRange:inTextContainer:rectCount: or the glyph-based equivalent with a zero-length range; that is still available, but it has the limitation that only one insertion point can be obtained at a time. There are many cases in which one wishes to retrieve multiple insertion points at once--for example, when one is trying to move from one to another. The method
- (NSUInteger)getLineFragmentInsertionPointsForCharacterAtIndex:(NSUInteger)charIndex
alternatePositions:(BOOL)aFlag
inDisplayOrder:(BOOL)dFlag
positions:(CGFloat *)positions
characterIndexes:(NSUInteger *)charIndexes;
allows clients to obtain all insertion points for a line fragment in one call. The caller specifies the line fragment by supplying one character index within it, and can choose whether to obtain primary or alternate insertion points, and whether they should be in logical or in display order. The return value is the number of insertion points returned. Each pointer passed in should either be NULL, or else point to sufficient memory to hold as many elements as there are insertion points in the line fragment (which cannot be more than the number of characters + 1). The positions buffer passed in will be filled in with the positions of the insertion points, in the order specified, and the charIndexes buffer passed in will be filled in with the corresponding character indexes. Positions indicate a transverse offset relative to the line fragment rect's origin. Internal caching is used to ensure that repeated calls to this method for the same line fragment (possibly with differing values for other arguments) will not be significantly more expensive than a single call.

Finally, there is a new NSLayoutManager delegate method,
- (NSDictionary *)layoutManager:(NSLayoutManager *)layoutManager
shouldUseTemporaryAttributes:(NSDictionary *)attrs
forDrawingToScreen:(BOOL)toScreen
atCharacterIndex:(NSUInteger)charIndex
effectiveRange:(NSRangePointer)effectiveCharRange;
This is sent when the layout manager is drawing and needs to decide whether to use temporary attributes or not. The delegate returns a dictionary of temporary attributes to be used, or nil to suppress the use of temporary attributes altogether. The effectiveCharRange argument is both an in and out by-reference effective range for those attributes. The default behavior if this method is not implemented is to use temporary attributes only when drawing to the screen, so an implementation to match that behavior would return attrs if toScreen is YES and nil otherwise, without changing effectiveCharRange.

NSTextView

A new property, allowedInputSourceLocales, controls the text input sources enabled for a NSTextView instance. The property can be accessed by the following accessor methods. There is a meta locale identifier, NSAllRomanInputSourcesLocaleIdentifier, available for specifying input sources that are limited for Roman script editing.
- (NSArray *)allowedInputSourceLocales;
- (void)setAllowedInputSourceLocales:(NSArray *)localeIdentifiers;
Command-delete is now bound to -deleteToBeginningOfLine:.


NSTextView Find Panel

The standard find panel for NSTextView now keeps track of the most recently used find and replace strings and displays them to the user in an NSComboBox.

In addition to communicating search strings via the find pasteboard, the standard find panel for NSTextView now also communicates search option metadata, including case sensitivity and substring matching options. This metadata is stored in a plist as the NSFindPanelSearchOptionsPboardType value on the global find pasteboard. As such, third party applications may store additional keys in this plist to communicate additional metadata as desired to support the various search options common to many third-party applications' find panels. NSTextView.h contains the AppKit-provided keys and values.

NSTextView Find Indicator

NSTextView now supports the new lozenge-style indication of find results, with a new method
- (void)showFindIndicatorForRange:(NSRange)charRange;
that causes a temporary indicator or indicators to appear around the visible portion(s) of the specified range. The indicators will automatically disappear after a certain period of time, or when the method is called again, or when any of a number of changes occur to the view (such as changes to text, to view size, or to view position). Note that this method does not itself scroll the specified range to be visible; any desired scrolling should be done before this method is called, first because the method acts only on the visible portion of the specified range, and second because scrolling will cause the indicators to disappear. Calling this method with a zero-length range will always remove any existing indicators.

Miscellaneous New NSTextView Methods

NSTextView includes a number of new flags for controlling its behavior.
- (void)setDisplaysLinkToolTips:(BOOL)flag;
- (BOOL)displaysLinkToolTips;
- (void)setAllowsImageEditing:(BOOL)flag;
- (BOOL)allowsImageEditing;
- (void)setAutomaticQuoteSubstitutionEnabled:(BOOL)flag;
- (BOOL)isAutomaticQuoteSubstitutionEnabled;
- (void)toggleAutomaticQuoteSubstitution:(id)sender;
- (void)setAutomaticLinkDetectionEnabled:(BOOL)flag;
- (BOOL)isAutomaticLinkDetectionEnabled;
- (void)toggleAutomaticLinkDetection:(id)sender;
The flag for displaying link tooltips controls whether the text view will automatically supply the destination of a link as a tooltip for text with a link attribute. The default value for this is YES; clients who do not wish this must explicitly disable it. In a related change, NSTextView will no longer automatically open file: URLs in links; by default, file: URLs will be revealed in the Finder. Clients wishing to override this should implement textView:clickedOnLink:atIndex: (as a delegate) or clickedOnLink:atIndex: (in a subclass).

The image editing flag controls whether text attachments representing images should allow their contents to be edited inline in the text, provided they support this and the text view is editable. Stock text attachments currently do not have support for this feature, but may do so in the future.

Automatic quote substitution, when it is turned on, causes ASCII quotation marks and apostrophes to be automatically replaced on a context- and language-dependent basis with more typographically accurate symbols. Automatic link detection, when it is turned on, causes strings representing URLs typed in the view to be automatically made into links to those URLs. In addition, the existing smart copy/paste functionality has a newly publicized action method,
- (void)toggleSmartInsertDelete:(id)sender;
In support of automatic link detection, there is a new method on NSAttributedString,
- (NSURL *)URLAtIndex:(NSUInteger)location effectiveRange:(NSRangePointer)effectiveRange;
that returns a URL from the contents of text at the given location, if the text at the location appears to be a string representing a URL. The effective range is the range of the URL string, or of non-URL text if no apparent URL is found.

To go along with the new NSLayoutManager insertion point functionality, there is a new NSTextView method
- (NSUInteger)characterIndexForInsertionAtPoint:(NSPoint)point;
which takes a point in view coordinates and returns a character index appropriate for placing a zero-length selection for an insertion point when the mouse is over the given point. NSTextInput protocol methods generally are not suitable for uses other than those associated with text input methods, and the NSTextInput protocol method characterIndexForPoint: is no exception; it is intended only for usages related to text input methods. The new characterIndexForInsertionAtPoint: should be used for insertion points associated with mouse clicks, drag events, and so forth. For other purposes, it is better to use NSLayoutManager methods, as demonstrated in a variety of code examples.

There is a new NSTextView delegate method
- (NSMenu *)textView:(NSTextView *)view menu:(NSMenu *)menu forEvent:(NSEvent *)event atIndex:(NSUInteger)charIndex;
which allows clients to control the context menu via the delegate, instead of having to subclass and override menuForEvent:. The menu parameter is the context menu that NSTextView would otherwise provide, and the charIndex argument is the index of the character that was right-clicked.

Finally, there is a new pasteboard type used by NSTextView when copying and pasting multiple selections.
NSString *NSMultipleTextSelectionPboardType;
This type is used only when the pasteboard is representing a multiple selection. The contents for this type should be an array of NSNumbers, one for each subrange of the selection, indicating the number of paragraphs contained in each subrange. The plain or rich text contents of the pasteboard will be a string representing the contents of each subrange concatenated with paragraph breaks in between them (where they do not already end in paragraph breaks); that combined with the paragraph counts in the NSMultipleTextSelectionPboardType is sufficient to determine which portions of the contents are associated with which subrange. This mechanism has been chosen because it is consistent across plain and rich text, and across different representations of rich text. The counts may be checked for consistency by comparing the total number of paragraphs in the plain or rich text contents of the pasteboard with the total of the numbers in the NSMultipleTextSelectionPboardType array; if the two do not match, then the NSMultipleTextSelectionPboardType contents should be ignored.

Additional List Styles

In Tiger, NSTextList marker formats supported the following numbering specifier keywords: decimal, lower-roman, upper-roman, lower-alpha, upper-alpha, lower-hexadecimal, upper-hexadecimal, and octal. In addition, it also supported the following constant specifier keywords: box, check, circle, diamond, disc, hyphen, square. These keywords are aligned with the corresponding draft CSS3 list-style-type values. In Leopard, NSTextList marker formats also support the following additional numbering specifier keywords: decimal-leading-zero, lower-greek, upper-greek, lower-russian, upper-russian, cjk-ideographic, hiragana, hiragana-iroha, katakana, katakana-iroha, cjk-earthly-branch, and cjk-heavenly-stem.

NSTypesetter

There is a new NSLayoutManager-interface API superseding -layoutGlyphsInLayoutManager:startingAtGlyphIndex:maxNumberOfLineFragments:nextGlyphIndex:. NSLayoutManager sends this message to the typesetter when its -allowsNonContiguousLayout setting is YES.
- (NSRange)layoutCharactersInRange:(NSRange)characterRange
forLayoutManager:(NSLayoutManager *)layoutManager
maximumNumberOfLineFragments:(NSUInteger)maxNumLines;

The last visible line truncation

The Cocoa Text System now allows the last visible line to have an ellipsis character appended if the entire content cannot fit into the specified bounding box. The behavior can be controlled with -truncatesLastVisibleLine for text cells. The -lineBreakMode must be either NSLineBreakByWordWrapping or NSLineBreakByCharWrapping for this option to take effect.. Also, the NSStringDrawingTruncatesLastVisibleLine flag can be specified to NSStringDrawing APIs that take NSStringDrawingOptions. The NSStringDrawingUsesLineFragmentOrigin flag must also be specified for the truncation flag to take effect.
- (BOOL)truncatesLastVisibleLine;
- (void)setTruncatesLastVisibleLine:(BOOL)flag;

NSFont

The AppKit framework no longer retains NSFont instances, and they are subject to the standard retain/release scheme. For debugging purpose, you can use the NSDisableFontDeallocation key. When the value is YES, font instances are not deallocated. Also, by setting NSFontDebugLevel to non-0 value, memory space previously occupied by NSFont is more aggressively reclaimed to allow finding over-released instances easily.

NSFontDescriptor

There is a new font descriptor matching API -matchingFontDescriptorWithMandatoryKeys: that returns the most suitable normalized instance.

We're allowing the following attribute and dictionary keys. They allow applications to create font descriptors that have non-default font feature settings.
NSString *NSFontFeatureSettingsAttribute;
NSString *NSFontFeatureTypeIdentifierKey;
NSString *NSFontFeatureSelectorIdentifierKey;

NSFontManager

NSFontManager now has the following 4 new public methods. You can use -currentFontAction and -convertFontTraits: to determine the action -convertFont: would perform. With the new accessor methods for the target property, you can now redirect the target for the action invoked by -sendAction method.
- (NSFontAction)currentFontAction;
- (NSFontTraitMask)convertFontTraits:(NSFontTraitMask)traits;
- (void)setTarget:(id)aTarget;
- (id)target;

RTF Handling

The RTF writer now prefers Microsoft font encodings over Mac scripts. The generated RTF data has much better compatibility with RTF reader implementations on Windows.


NSInputManager

The automatic loading of bundles located in InputManagers folders is now officially unsupported. The conditions for valid input manager bundle is further tightened. This functionality is likely to be disabled in a future release.

1. The valid installation is now restricted to the /Library/InputManagers folder only. Bundles in other locations are silently ignored.

2. All the files in the bundle and /Library/InputManagers folder itself must be owned by the root user and admin group. No files inside the bundle can have group or other write permissions.

3. Processes running with the root privilege (getuid() == 0 or geteuid() == 0) cannot load any bundle input manager.

4. Processes running with the wheel group privilege cannot load any bundle input manager.

5. The process must be in the active workspace session at the time of loading the bundles.

6. The process must not be tainted by changing user or group id (checked by issetugid()).

7. No 64-bit processes can load any bundle input managers.

NSTextInputClient protocol

There is a new protocol, NSTextInputClient, for objects willing to participate in the Cocoa Text Input system. The protocol supersedes the old protocol, NSTextInput, and allows conforming objects to take advantage of various system supplied functionalities. The Cocoa framework uses the new protocol whenever it is adopted by the responder object. For NSTextView subclasses, the new protocol is preferred unless any of the NSTextInput methods is overridden and none of the new methods is overridden.

There is now a public attributed string property, NSMarkedClauseSegmentAttributeName, to communicate clause segments inside marked text.


Spelling and Grammar Checking

Grammar checking is a new feature associated with the existing spellchecking functionality. Any spellchecking server has the option of also providing grammar checking, by implementing the NSSpellServer delegate method
- (NSRange)spellServer:(NSSpellServer *)sender checkGrammarInString:(NSString *)stringToCheck
language:(NSString *)language details:(NSArray **)details;
The return value is intended to be the range of the next sentence or other grammatical unit that contains sections to be flagged for grammar, since grammar checking generally must be performed sentence by sentence. The details argument optionally returns by reference an array of dictionaries, each one describing a grammatical issue detected in the sentence (since a single sentence may contain more than one problem). In these dictionaries the following keys will be recognized:
NSString *NSGrammarRange;
NSString *NSGrammarUserDescription;
NSString *NSGrammarCorrections;
The value for the NSGrammarRange key should be an NSValue containing an NSRange, a subrange of the sentence range used as the return value, whose location should be an offset from the beginning of the sentence--so, for example, an NSGrammarRange for the first four characters of the overall sentence range should be {0, 4}. The value for the NSGrammarUserDescription key should be an NSString containing descriptive text about that range, to be presented directly to the user; it is intended that the user description should provide enough information to allow the user to correct the problem. A value may also be provided for the NSGrammarCorrections key, consisting of an NSArray of NSStrings representing potential substitutions to correct the problem, but it is expected that this may not be available in all cases. It is recommended that NSGrammarUserDescription be supplied in all cases; in any event, either NSGrammarUserDescription or NSGrammarCorrections must be supplied in order for something to be presented to the user. If NSGrammarRange is not present, it will be assumed to be equal to the overall sentence range. Additional keys may be added in future releases.

The corresponding client method on NSSpellChecker is
- (NSRange)checkGrammarOfString:(NSString *)stringToCheck
startingAt:(NSInteger)startingOffset
language:(NSString *)language
wrap:(BOOL)wrapFlag
inSpellDocumentWithTag:(NSInteger)tag
details:(NSArray **)details;
similar to the existing spellchecking methods. NSSpellChecker also has a new method,
- (NSArray *)availableLanguages;
suitable for use with the existing -language and -setLanguage:. This returns the list of available languages for spellchecking, in the forms specified by the spelling servers; usually these will be language abbreviations such as "fr" or "en_GB", of the sort used by NSBundle for identifying localizations. The -setLanguage: method preferentially accepts one of these, but will attempt to find an inexact match for any value it is given. Also new are the NSSpellChecker methods
- (void)learnWord:(NSString *)word;
- (BOOL)hasLearnedWord:(NSString *)word;
- (void)unlearnWord:(NSString *)word;
that allow clients access to the learning and unlearning features of the spellchecker. The learnWord: method is not actually new, but is newly public; it has always been present on NSSpellChecker. The other methods are new, but there was a previous equivalent of unlearnWord:, named forgetWord:.

NSTextView has methods to control its use of grammar checking,
- (void)setGrammarCheckingEnabled:(BOOL)flag;
- (BOOL)isGrammarCheckingEnabled;
- (void)toggleGrammarChecking:(id)sender;
If grammar checking is enabled, then it will be performed alongside spellchecking, whenever the text view checks spelling, whether continuously or manually.

Means are also now provided to control the display of the spelling and grammar indicators on text, used to highlight portions of the text that are flagged for spelling or grammar issues. These regions are denoted by a temporary attribute on the layout manager, using the key
NSString *NSSpellingStateAttributeName;
This key is available going back to Mac OS X 10.2, but its interpretation has changed. Previously, any non-zero value would cause the spelling indicator to be displayed. For Mac OS X 10.5, the (integer) value will be treated as being composed of the following flags:
enum {
NSSpellingStateSpellingFlag = (1 << 0),
NSSpellingStateGrammarFlag = (1 << 1)
};
There is a new method on NSTextView for setting the spelling state, which may be called by clients or overridden by subclassers.
- (void)setSpellingState:(NSInteger)value range:(NSRange)charRange;
This method in turn calls a new NSTextView delegate method,
- (NSInteger)textView:(NSTextView *)textView shouldSetSpellingState:(NSInteger)value range:(NSRange)affectedCharRange;
which allows the delegate to control any change in the value of the spelling state.


Text and image effects: -[NSCell backgroundStyle]

Prior to Leopard, you may have noticed that text turns white in selected table view rows. The mechanism that controlled this behavior, unfortunately, was arcane. The table would set the highlight color of the cell to the alternateSelectedControlColor and set the cell to be highlighted. The cell would then introspect its highlight color, and use white text if the color was the alternateSelectedControlColor.

Another text effect occurred in applications such as 10.4's Address Book. Text looked engraved when drawn on the metal window surface. This was done with custom drawing.

For Leopard, this kind of behavior is formalized and extended with an API, -[NSCell setBackgroundStyle:]. This provides a cell with metadata that can be used to make good decisions about drawing. There are only four possible background styles: light, dark, raised and lowered. Most backgrounds are light. Selected table rows are, for 10.5, dark, so text will draw white. A metal surface is raised, so text that draws directly on it should look engraved. Some surfaces are lower than the plane of cell drawing, in which case text should look embossed.

There are a few methods involved. -[NSCell backgroundStyle] describes the background drawn on in the method -[NSCell drawWithFrame:inView:]. -[NSCell interiorBackgroundStyle] describes the background drawn on in the method -[NSCell drawInteriorWithFrame:inView:]. What's the difference? -[NSCell drawWithFrame:inView:] is the primary top level cell drawing method - it draws the whole cell. One of the methods it calls is -[NSCell drawInteriorWithFrame:inView:], which draws interior content like text and images. If a button draws a bezel, then -[NSCell backgroundStyle] will describe the surface the button is drawing on, while -[NSCell interiorBackgroundStyle] will describe the surface of the bezel itself.

Consider the bookmarks buttons in Safari 3.0. This is a standard style of button available in Interface Builder. The buttons are placed on a metal-ish surface that is raised relative to the button, so the -backgroundStyle is NSBackgroundStyleRaised. When the button is rolled over or clicked, it draws a bezel, and the bezel appears to be lower than the interior content of the button. So, when the button is not rolled over, -interiorBackgroundStyle returns NSBackgroundStyleRaised and the text looks engraved. When the button is rolled over, -interiorBackgroundStyle returns NSBackgroundStyleLowered and the text looks embossed.

This also makes it clear why a method to directly ask a cell to draw white, or engraved, or embossed would be inappropriate. The only cells that should get white text in a selected table row are those that do not interpose any drawing between the surface of the table and the text. Only a cell itself knows whether that is the case.

The complete list of backgroundStyle-related methods for Leopard is -[NSCell backgroundStyle], -[NSCell setBackgroundStyle:], -[NSCell interiorBackgroundStyle], and -[NSSegmentedCell interiorBackgroundStyleForSegment:].

Text and image effects: -[NSCell backgroundStyle] developer responsibilities

The main idea with background styles is this: "The developer who knows what art looks like is responsible for describing it to whatever draws on top." Often, it's AppKit that draws the art. All buttons that draw bezels will describe them with the return from -[NSButtonCell interiorBackgroundStyle]. If you pay attention to this value, you will get some independence from changes in framework art when doing custom drawing on a button surface. This might include choosing an image to draw, or even processing an image with CoreImage filters chosen based on backgroundStyle and other state.

Similarly, if you have a custom button bezel, you should override -interiorBackgroundStyle to describe the artwork you draw. This will ensure that AppKit renders appropriate effects on top of the bezel. You shouldn't rely on your art having the same general look as drawing that you've overridden - the framework art could change in a release, leaving you out of sync.

There is no setter for -[NSButtonCell interiorBackgroundStyle] because the return value could only be incorrect if you override cell drawing. If you override cell drawing, you can override -interiorBackgroundStyle as well.

Generally, it's the control's responsibility to call -[NSCell setBackgroundStyle:] on a cell right before drawing it. For example, NSTableView will set a backgroundStyle on its cells before it draws them. This is typically light or dark, but may also be raised or lowered in the case of group rows in source lists, and potentially elsewhere. If you have a custom control subclass, you should call -setBackgroundStyle on your cells before drawing them.

A caveat: Most AppKit controls do no drawing of their own. The cell does all the drawing. In these cases, you'd want a backgroundStyle of the superview to be inherited on the subview in some fashion, but there is no support for this in Leopard. So, in some cases you'll have to help, and sometimes hardwire a background style that it'd be nicer to introspect. For example, if you place an borderless NSTextField directly on the window surface you will likely want to have a controller call setBackgroundStyle:NSBackgroundStyleRaised on the text cell to get engraved text. Button cells and segmented cells that are usually used in a particular context have an initial backgroundStyle that matches that use, but feel free to change it if it isn't correct. For example, buttons with NSRecessedBezelStyle start out with NSBackgroundStyleRaised.


Text and image effects: -[NSImage isTemplate]

So far we've mostly talked about text. Images drawing in cells also have visual effects applied. For example, images are automatically dimmed out in disabled cells and darkened when pressed.

This is extended in Leopard with a new metadata property, -[NSImage isTemplate]. An image is a 'template' if it is a black and clear mask that should not be presented to the user directly, but always processed into a final form. It's similar to a glyph in a font. If a cell is given a template image, it can perform much more sophisticated effects than usual, similar to those done with text. The image can be dark most of the time, white in a selected table view row, and engraved or embossed the same way text is.

The template property does not affect the way an image draws. It's metadata that a sophisticated client can look at. The only sophisticated client in AppKit for 10.5 is NSCell. If you need to produce an NSImage with effects pre-rendered, draw with a cell into an image.

A good example of template image processing occurs in the button that shows the bookmarks collections in Safari 3.0. This is very much a stock AppKit button. There's a single template image set on it, which is an icon of a book. That single image appears engraved or embossed depending on whether button is rolled over (really, on the -interiorBackgroundStyle of the cell).

To mark an image as a template, call -[NSImage setTemplate:]. As a convenience, in applications linked on or after 10.5, any image read off of disk via -[NSImage imageNamed:] whose name ends in @"Template" will be marked as a template as it is created. This makes it easy to use template images in Interface Builder. Just make sure your image filenames end in "Template".

One particular effect is worth calling out, because you'll see it and likely wonder exactly what triggers it: If a template image is drawing on a raised background and is also supposed to look on, it will draw with a blue glow. Think of the image as a translucent gray piece of plastic cut into the surface of the cell, with a blue backlight behind it when the cell is on. This will happen, for example, in selected segments of an NSSegmentedControl with NSSegmentStyleTexturedRounded and NSSegmentSwitchTrackingSelectAny (which means that segments behave like check boxes). You cannot rely on this glow occurring in any particular place because framework art can change, but AppKit promises to continue to do something appropriate.

For an NSButtonCell, a cell's -image will be processed to look 'on' if the cell's state is NSOnState, its showsStateBy mask contains NSContentsCellMask (which means 'use alternate image and title when on'), and it doesn't have an alternateImage. In Interface Builder, make a 'Toggle' button and give the button an image. This also sets up the highlightsBy mask, but it's likely to be what you want.

You may note that it isn't possible to both use a distinct piece of art as an alternateImage on a button or segmented control and also get the blue glow. This may be somewhat limiting, but should tend to make sure this effect is only used when appropriate. This effect helps the user to distinguish between a button that shows an action and a button that shows the state of something. Most buttons in the OS are actions. However, it has always been hard to distinguish those buttons that give state. The blue glow communicates state very effectively. Look at the calendar button in the lower left corner of iCal in 10.5. When the mini calendar pane isn't shown, the button shows an engraved mini-calendar. The user might think of this as either an action 'show mini-calendar' or as a state, 'mini-calendar is off'. Luckily, both interpretations agree on the effect of clicking the button - it should show the calendar. Once the user clicks the button, the correct interpretation becomes very clear: The calendar icon glows blue when the pane is shown. This is obviously showing state, and users will realize that if they click again then the button will turn off and the calendar pane will be hidden.

Text and image effects: NSStatusItem

It's worth mentioning separately that NSStatusItem is template image savvy. If you use template images for your status items, you will get rendering appropriate for the look of the menu bar in Leopard and beyond. Unfortunately, if you use a custom view in a status item, we do not have API to propagate a background style from the status item to the view. You will have to hardwire the background styles.

NSButton metrics

-[NSButton sizeToFit] applied to buttons with bezel style NSRecessedBezelStyle or NSRoundRectBezelStyle now produces buttons which are two pixels narrower than the buttons produced on Tiger. The new buttons have the same dimensions as those in Safari's bookmarks bar.

sizeToFit is substantially different for buttons with NSCircularBezelStyle for applications linked on and after Leopard. The Tiger 'regular' size for this button was very large, really too large to be used anywhere. What was called the 'small' size was something that would generally be called 'regular', and looked correct next to other regular sized controls.

In Leopard, buttons with NSCircularBezelStyle are available in regular, small and mini sizes where the art for the small and mini sizes is new, and the regular size is what used to be called small. For compatibility, the art chosen at draw time is no longer based on the marked controlSize of the button cell, it's based on the size of the frame in which the cell is drawn. The largest art that fits in the provided frame will be used, including the very large art that was available in Tiger. The upshot is that (1) existing buttons should continue to draw they way they did, (2) new buttons will be smaller. It is a bad idea, however, to call sizeToFit at runtime on circular buttons in an app linked on Leopard but that has to run on Tiger as well. The sizeToFit call will produce visually different buttons when running on Tiger vs Leopard. If you need to do this, write your own sizing routine and call it instead of sizeToFit.


Standard images

Leopard includes a number of standard images that developers may find useful. These images are available as names for use with -[NSImage imageNamed:]. For example, NSImageNameBookmarkTemplate is the image used in Safari for the button that shows the bookmark collections view. See NSImage.h for all of the names.

The string values of the constants are also documented so that the images can be used in Interface Builder. The string corresponding to NSImageNameBookmarkTemplate is @"NSBookmarkTemplate". Note that this image is a template and conforms to the template naming convention, as discussed in the release notes section on -[NSImage isTemplate].

Most images are named by a specific function or situation where they are intended to be used. In some cases, the artwork may be more generic than the name. For example, the image for NSImageNameInvalidDataFreestandingTemplate is an arrow in 10.5. Please do not use an image outside of the function for which it is intended - the artwork can change between releases. The invalid data image could change to a yellow exclamation-point-in-triangle icon. If there is no image available for the situation you're interested in, please file a bug and use your own custom art in the meantime.

There is an informal naming convention used with some images. If an image has "Freestanding" in the name, it's usable as a small inline image without any additional bezel. For example, Safari uses NSImageNameStopProgressTemplate (an X for 10.5) as the stop button in a bezeled button in the toolbar, while it uses NSImageNameStopProgressFreestandingTemplate (X in a circle for 10.5) in the downloads window where it appears inline with a progress indicator.

The standard images are mostly provided as a convenience. Use them if they fit your need, but if they don't then custom art is okay. For example, you may find that you want a different stroke weight for a larger or smaller image with an "add" or "remove" button. It'd be great if AppKit could accommodate that, but use your own art if it's better.

Standard Images: -[NSButtonCell setImageScaling:] and -[NSSegmentedCell setImageScaling:forSegment:]

One major caveat with the standard images is that their size is not guaranteed to stay the same between releases. Also, since they're supposed to be used in multiple contexts, you may find that the original size of an image is inappropriate for your use.

To help with this, NSButton and NSButtonCell have gained an imageScaling property, and NSSegmentedControl and NSSegmentedCell have gained -imageScalingForSegment: and -setImageScaling:forSegment: methods.

These behave similarly to the imageScaling property of NSImageCell. A button can now be configured to always draw its image scaled such that it fits in the available space. This will ensure that even if an image gets larger, it will still fit in your button. This is something of a backup fail safe, since many images have narrow lines that will not look good scaled, but it does provide a level of safety that would otherwise be a pain. All new buttons and segmented controls created in interface builder will have NSImageScaleProportionallyDown set by default.

Image scaling has no bearing on -sizeToFit behavior.

We also changed the values available in the NSImageScaling enumeration, because we needed one value that wasn't available, and two of the existing values were not well named.
enum {
NSImageScaleProportionallyDown = 0, // Scale image down if it is too large for destination. Preserve aspect ratio.
NSImageScaleAxesIndependently, // Scale each dimension to exactly fit destination. Do not preserve aspect ratio.
NSImageScaleNone, // Do not scale.
NSImageScaleProportionallyUpOrDown // Scale image to maximum possible dimensions while (1) staying within destination area
// and (2) preserving aspect ratio
};
typedef NSUInteger NSImageScaling;

NSImage layout metadata

NSImage now supports an alignmentRect property, which provides metadata that a client may use to help determine layout. The bottom of the rect gives the baseline of the image. The other edges give similar information in the other directions.
- (NSRect)alignmentRect;
- (void)setAlignmentRect:(NSRect)rect;
The alignmentRect of an image has no effect on methods such as drawInRect:fromRect:operation:Fraction: or drawAtPoint:fromRect:operation:fraction:. Rather, an interested client may use the alignmentRect to improve layout where applicable.

A 20x20 image of a phone icon with a glow might specify an alignmentRect of {{2,2},{16,16}} that excludes the glow. NSButtonCell will take advantage of the alignmentRect to place the image in the same visual location as an 16x16 phone icon without the glow. A 5x5 star that should render high when aligned with text might specify a rect of {{0,-7},{5,12}}.

The default alignmentRect of an image is {{0,0},imageSize}. The rect is adjusted when setSize: is called.

Multipart image drawing

NSCell.h contains two new functions for use with custom cell drawing, though they may be useful elsewhere as well.

NSDrawThreePartImage is used to draw a button of fixed height and variable width, or vice versa. It takes two end caps and a center image to be tiled.

NSDrawNinePartImage is used to draw something like a box that can be drawn at any height or width. It takes four corner images, four images to tile along the edges, and an image to tile in both directions for a center fill.

It's a good idea to use these functions for your custom drawing. AppKit can take care to get resolution independence issues right, and there are some subtle issues.

NSCell Automatic Expansion ToolTip Frame

NSCell has some new API to support expansion tool tips in certain controls:
- (NSRect)expansionFrameWithFrame:(NSRect)cellFrame inView:(NSView *)view;
- (void)drawWithExpansionFrame:(NSRect)cellFrame inView:(NSView *)view;
An expansion tool tip allows one to see truncated text in a special floating window that is similar but different from a normal ToolTip. Currently, NSTableView, NSOutlineView and NSBrowser display expansion tool tips when the text is truncated. If you have a cell that will be displayed in one of these controls, it is recommended that you implement the above methods to properly support the expansion tool tip feature. By default, the methods are properly implemented in NSTextFieldCell and NSBrowserCell. NSCell will always return NSZeroRect, and prevent the expansion from happening. For an example of how to implement it, see the SimpleBrowser demo app.

Clients of NSTableView, NSOutlineView and NSBrowser can prevent the cell expansion from happening on a particular row/column by using the new delegate methods declared in the appropriate header files.

NSCell Marked Text Support

Changing the content of NSCell subclasses no longer forces confirming the marked text (also known as the inline hole) unless the new content is actually different from the original.

There is a new NSCell API telling its field editor to post text change notifications. NSTextFieldCell also provides -setWantsNotificationForMarkedText:
- (BOOL)wantsNotificationForMarkedText;
The bug introduced in Tiger that NSCell's various sizing methods such as -cellSizeForBounds: ignoring bounds sizes smaller than 0.0 is fixed.

NSTextFieldCell

-[NSTextFieldCell accessibilityPerformAction:] now tries to perform NSAccessibilityConfirmAction for cells with no associated action. It uses -currentEditor and -selectedCell to determine if the current field editor is bound to self.

A new property, allowedInputSourceLocales, controls the text input sources enabled for the NSTextView instance. The property can be accessed by the following accessor methods. There is a meta locale identifier, NSAllRomanInputSourcesLocaleIdentifier, available for specifying input sources that are limited for Roman script editing.
- (NSArray *)allowedInputSourceLocales;
- (void)setAllowedInputSourceLocales:(NSArray *)localeIdentifiers;
NSTextFieldCell no longer disables itself temporarily in -trackMouse:inRect:ofView:untilMouseUp:. It is the application's responsibility now to properly set up the action invocation configuration via -sendActionOn: method.

In order to prevent inconsistent rendering, background color rendering is disabled for rounded-bezel NSTextFieldCell instances.

Autorelease pool in -[NSCell trackMouse:inRect:ofView:untilMouseUp:]

For applications linked on or after Leopard, NSCell uses an internal autorelease pool while looping over events in -trackMouse:inRect:ofView:untilMouseUp:. This should have no effect on an app that already practices correct memory management, except that memory usage will not temporarily climb while a user, say, scrubs an NSSlider back and forth. However, an application that isn't always careful about memory management may have newly expressed bugs. If pressing a button causes an NSTableView delegate to receive a final autorelease, and the programmer is not careful to call [tableView setDelegate:nil] to clear the non-retained back reference, the app could crash if the tableview tries to message its datasource before the end of the runloop cycle.

Archive reading for very old cells

Prior to Leopard, NSCell had residual support for reading very old un-keyed archive data saved prior to Mac OS X 10.0. This support has been removed. An attempt to read such an NSCell will now throw an exception. By the way, in case you missed it, you should really be using keyed archiving. The unkeyed archiver does not save out any object properties added in the last several OS releases. If we did, those archives would not be readable on earlier versions of the OS.


NSBitmapImageRep - Creating with a Custom Color Profile

It is now possible to create an NSBitmapImageRep with an arbitrary ICC color profile. The specified profile will be used when the image is drawn, and will also be saved with the image when it is encoded to a bitmapped image data format such as TIFF.

To do this for an NSBitmapImageRep that is created from scratch using one of the "-initWithBitmapDataPlanes:..." initializer methods, client code should pass NSCalibratedRGBColorSpace to the initializer, and then provide the ICC profile data as an NSData object using the -setProperty:withValue: method and the NSImageColorSyncProfileData property key:
NSBitmapImageRep *bitmapImageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:planes
/* ...more parameters... */
colorSpaceName:NSCalibratedRGBColorSpace
/* ...more parameters... */
];
[bitmapImageRep setProperty:NSImageColorSyncProfileData withValue:iccProfileData];
One can also set a new replacement color profile for an NSBitmapImageRep that is initialized from an existing TIFF, PNG, etc. file using the same "-setProperty:withValue:" technique.

An ICC profile can be obtained as NSData from an NSColorSpace instance using the "-ICCProfileData" accessor method:
NSColorSpace *colorSpace = [NSColorSpace sRGBColorSpace];
NSData *iccProfileData = [colorSpace ICCProfileData];
It can also be obtained by initializing an NSData instance with the contents of an ".icc" profile file:
NSData *iccProfileData = [NSData dataWithContentsOfFile:@"/System/Library/ColorSync/Profiles/sRGB Profile.icc"];

NSBitmapImageRep - Creating from a CIImage

AppKit now includes an initializer method for creating an NSBitmapImageRep from a Core Image CIImage object:
- (id)initWithCIImage:(CIImage *)ciImage;
The CIImage is required to be of finite extent (if not, -initWithCIImage: raises an exception). The -initWithCIImage: method produces an NSBitmapImageRep whose pixel dimensions equal the incoming CIImage's extent.

Note that if the given CIImage is the result of a Core Image filter operation whose evaluation has been deferred, invoking -initWithCIImage: will cause the image recipe to be evaluated (rendered) so that the resultant image pixels can be obtained, so this method may be expected to take some time to execute and return, depending on the complexity of the filter chain and the availability of Core Image-accelerating graphics hardware on the host system.

NSBitmapImageRep - Creating from a CGImage, Getting a CGImage

AppKit also includes a new initializer method for creating an NSBitmapImageRep from a Quartz CGImage:
- (id)initWithCGImage:(CGImageRef)cgImage;
An NSBitmapImageRep that is created in this way retains the given CGImage as its primary underlying representation, reflecting the CGImage's properties as its own and using the CGImage to draw when asked to draw.

Since the CGImageRef is simply retained by the NSBitmapImageRep, its resident image data is referenced instead of being copied. If the NSBitmapImageRep is asked for its pixel data (via a -bitmapData or -getBitmapDataPlanes: message), it will oblige by unpacking a copy of the CGImage's content to an internal buffer. The resultant pixel data should be considered read-only. Changing it through the returned pointer(s) will not cause the CGImage to be re-created.

Regardless of how it was created, an NSBitmapImageRep can now be asked to return an autoreleased CGImage representation of itself:
- (CGImageRef)CGImage;
Using this method may cause the CGImage to be created, if the NSBitmapImageRep does not already have a CGImage representation of itself. Once created, the CGImage is owned by the NSBitmapImageRep, which is responsible for releasing it when the NSBitmapImageRep itself is deallocated.

NSBitmapImageRep - Fallback Background Color for JPEG output

NSBitmapImageRep.h declares an additional NSBitmapImageRep attribute, available on Leopard, that can be used to specify a fallback background color to use when encoding an image to a data/file format that doesn't support alpha channels:
NSString* NSImageFallbackBackgroundColor  AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // JPEG output (NSColor)
This allows clients to specify the background color to use for the image data that's written out, in the event that the NSBitmapImageRep being encoded has an alpha channel. It corresponds to the kCGImageDestinationBackgroundColor property defined by the ImageIO framework.


New NSBox properties

NSBox now supports generic colored box drawing via four new properties:
- (CGFloat)borderWidth;
- (void)setBorderWidth:(CGFloat)borderWidth;
- (CGFloat)cornerRadius;
- (void)setCornerRadius:(CGFloat)cornerRadius;
- (NSColor *)borderColor;
- (void)setBorderColor:(NSColor *)borderColor;
- (NSColor *)fillColor;
- (void)setFillColor:(NSColor *)fillColor;
These properties only apply to boxes of type NSBoxCustom. The word 'custom' refers to these boxes having nothing to do with the human interface guidelines for Mac OS X. As such, the style should be used sparingly. It may be useful for simple custom drawing, or as a placard of some sort, but should not be used as a general control grouping box.

This box style may be useful in conjunction with the new Leopard class NSCollectionView. NSCollectionView supports single and multiple selection, but doesn't draw anything to indicate selection itself. That responsibility is delegated to the views it contains. A custom box can be used to draw a simple selection highlight.

One problem with a using NSBox to draw the selection highlight in NSCollectionView is that one needs to be able to toggle drawing on and off corresponding to the selected property of NSCollectionViewItem. To support this case, we've added one more property to NSBox:
- (BOOL)isTransparent;
- (void)setTransparent:(BOOL)flag;
Bind the transparent property to the selected property of NSCollectionViewItem. The semantics of NSBox's transparent property of are the same as the semantics of NSButton's transparent property.


NSGradient

Instances of the new NSGradient class support the creation of a color gradient with multiple color stops, and drawing itself as a linear or or radial gradient. A gradient defines a transition between colors at locations from 0.0 to 1.0. The starting color is considered to be at location 0.0, the ending color at 1.0. Additional color stops can be located at positions between 0.0 and 1.0. The color gradient is able to draw itself in a variety of ways, as a linear gradient and as a radial gradient.

The designated initializer takes an NSArray of colors for the gradient and a C array containing CGFloats with values between 0.0 and 1.0 to indicate the locations of the colors within the gradient. In addition, the color space of the gradient is provided. All provided colors will converted to this color space. If no color stop is located at 0.0 or 1.0, the color of the nearest color stop will be drawn to the appropriate end of the gradient.
- (id)initWithColors:(NSArray *)colorArray atLocations:(CGFloat *)locations colorSpace:(NSColorSpace *)colorSpace;
Three additional initializers handle common cases. The first takes a start and end color to create a two-color gradient. The second takes an array of colors, and will space the provided colors at equal intervals from 0.0 to 1.0. The third takes a nil-terminated variable length list of color/location pairs. The generic RGB color space will be used for gradients created with these init methods.
- (id)initWithStartingColor:(NSColor *)color endingColor:(NSColor *)endingColor;
- (id)initWithColors:(NSArray *)colorArray;
- (id)initWithColorsAndLocations:(NSColor *)firstColor, ...;
Once a color gradient is defined, it can be used to draw both linear and radial gradients.

Drawing methods allow for the drawing of linear and radial gradients within a rectangle and path. Given a rectangle or path, the convenience method will calculate appropriate locations and do the appropriate clipping.

For linear gradients, the angle of the gradient within the rect or path can be specified.
- (void)drawInRect:(NSRect)rect angle:(CGFloat)angle;
- (void)drawInBezierPath:(NSBezierPath *)path angle:(CGFloat)angle;
For radial gradients, a relative center position can be specified, using NSZeroPoint specifies a radial gradient centered within the rectangle or path bounding rect. The radial gradient drawn by these methods always draws from an inner point to an outer circle, with the inner point at the center of the outer circle.

The relative center position allows a developer to proportionally adjust the center of the radial gradient with respect to the rectangle or path bounding rect. The relative center position maps the point -(1.0, -1.0) to the origin of the rectangle and the point (1.0, 1.0) to the maximum x and y values of the rectangle. The center of the bounding rect maps to a relative center position of (0, 0).
- (void)drawInRect:(NSRect)rect relativeCenterPosition:(NSPoint)relativeCenterPosition;
- (void)drawInBezierPath:(NSBezierPath *)path relativeCenterPosition:(NSPoint)relativeCenterPosition;
These drawing methods provide an easy way to draw gradient fills. Developers who wish other drawing behavior can use the primitive drawing methods described below, and create additional convenience methods as categories which calculate where the primitive methods should draw.

Two primitive drawing methods map closely to the drawing of Quartz shadings. Note that, just as with Quartz shadings, these primitive drawing methods perform no clipping before drawing.

Each primitive drawing method takes an options: argument. Two options are defined:
    NSGradientDrawsBeforeStartingLocation
    NSGradientDrawsAfterEndingLocation
These options control whether drawing extends before and after the gradient start and end locations. These options are only present for the primitive drawing methods, since the rect and path-centric drawing methods ensure that the entire rect or path is filled by the gradient. These drawing primitive methods draw a linear gradient and a radial gradient, respectively.
- (void)drawFromPoint:(NSPoint)startingPoint toPoint:(NSPoint)endingPoint options:(NSGradientDrawingOptions)options;
- (void)drawFromCenter:(NSPoint)startCenter radius:(CGFloat)startRadius
toCenter:(NSPoint)endCenter radius:(CGFloat)endRadius options:(NSGradientDrawingOptions)options;

A number of methods are provided primarily to allow for the creation of controls that edit/create gradients. These methods return the number of color stops, access the color and location of each stop, return the color space of the gradient, and determine the interpolated color at a particular location between 0.0 and 1.0 in the color gradient.
- (NSInteger)numberOfColorStops;
- (void)getColor:(NSColor **)color location:(CGFloat *)location atIndex:(NSInteger)index;
- (NSColorSpace *)colorSpace;
Overriding this method to provide different color values will not affect the underlying calculation of the color gradient, and will not affect how the color gradient is drawn.
- (NSColor *)interpolatedColorAtLocation:(CGFloat)location;

NSTableView/NSOutlineView

NSTableView and NSOutlineView now properly handle alpha backgroundColors. In addition, you can set the color to [NSColor clearColor] to see through to the area behind you (ie: make it transparent), but note that you must also set drawsBackground to NO on the containing NSScrollView, such as: [[tableView enclosingScrollView] setDrawsBackground:NO].

The documentation correctly states that one can programatically select multiple rows even if allowsMultipleSelection was set to NO, but this was actually not allowed. On Leopard linked applications, this is fixed, and one can call [table selectRowIndexes:indexes byExtendingSelection:YES] or [table selectRow:row byExtendingSelection:YES] and correctly select multiple rows, even if allowsMultpleSelection is set to NO. The documentation correctly states that one can progmatically deselect all rows regardless of whether an empty selection is allowed, but this was actually not allowed. This is also fixed for Leopard linked applications.

Tables now support inter-cell navigation as follows:

- Tabbing forward to a table focuses the entire table.
- Hitting Space will attempt to 'performClick:' on a NSButtonCell in the selected row, if there is only one instance in that row.
- Tabbing again focuses the first "focusable" (1) cell, if there is one.
- If the newly focused cell can be edited, editing will begin.
- Hitting Space calls 'performClick:' on the cell and sets the datasource value afterwards, if changed. (2)
- If a text cell is editing, hitting Enter will commit editing and focus will be returned to the tableview, and Tab/Shift-tab will commit the editing and then perform the new tab-loop behavior.
- Tabbing will only tab through a single row
- Once the last cell in a row is reached, tab will take the focus to the next focusable control.
- Back tabbing into a table will select the last focusable cell.

(1) A focusable cell is generally defined as [cell isEnabled] && [cell isSelectable] in a table column that is editable. However, NSTextFieldCells also check if the row is selectable, and tableView:shouldEditTableColumn:row: returns YES (if implemented by the delegate). NSImageCells cannot be focused. NSButtonCells only check if the [cell isEnabled].
(2) To make this work with NSPopUpButtonCell, performClickWithFrame:inView: is called.

NSTableView/NSOutlineView - Delegate Changes

The following two new Leopard delegate methods introduced at WWDC have been renamed from:
- (NSIndexSet *)tableView:(NSTableView *)tableView
selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes
byExtendingSelection:(BOOL)extend;
- (NSIndexSet *)outlineView:(NSOutlineView *)outlineView
selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes
byExtendingSelection:(BOOL)extend;
to:
- (NSIndexSet *)tableView:(NSTableView *)tableView
selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes;
- (NSIndexSet *)outlineView:(NSOutlineView *)outlineView
selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes;
In releases prior to Mac OS 10.5, for the following delegate method:
- (void)tableView:(NSTableView*)tableView didDragTableColumn:(NSTableColumn *)column;
the tableColumn parameter would incorrectly be the NSTableColumn that existed at the dragged column's original index. For applications linked on or after Leopard, the tableColumn will correctly be the column that was dragged.

NSOutlineView requires all of its items to be pointer unique, however, between a reload items that have the same hash value and are considered [NSObject isEqual], will preserve the expanded state for those items, even if they are not pointer equal.

Prior to Leopard, NSTableView and NSOutlineView would not clear out the drag pasteboard before calling:
- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard;
or
- (BOOL)tableView:(NSTableView *)tableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pboard;
In Leopard, it will now clear out the pasteboard. You should declare the types you support for drag and drop with:
    NSMutableArray *types = [[pboard types] mutableCopy];
// Add our custom type and leave the ones NSOutlineView supports in the list.
[types addObject:MyType];
// Make ourselves the owner. For any types we don't handle we can forward to NSOutlineView/NSTableView.
[pboard declareTypes:types owner:self];
The new delegate method:
- (BOOL)tableView:(NSTableView *)tableView
shouldTrackCell:(NSCell *)cell
forTableColumn:(NSTableColumn *)column
row:(NSInteger)row;
allows a cell to be tracked, even if the row isn't selectable or selected. This allows you make a table view that will not allow any rows to be selected, but still allow the user to interact with the cells, as seen below (using outline view as an example):
- (BOOL)outlineView:(NSOutlineView *)ov shouldSelectItem:(id)item {
return NO;
}
- (BOOL)outlineView:(NSOutlineView *)ov shouldTrackCell:(NSCell *)cell forTableColumn:(NSTableColumn *)column item:(id)item {
return YES;
}
Another example is to not allow check box button cells to change the selection, but still allow them to be clicked on and tracked. [NSApp currentEvent] will always be correct when this method is called, and you may use it to perform additional hit testing of the current mouse location. See the DragNDropOutlineView demo application for an example of how to do this.

In outlineView:shouldSelectItem: and tableView:shouldSelectRow: you can now access clickedRow and clickedColumn to see what row and column was clicked on, if the method is being sent in response to an initial click event. At that point, [NSApp currentEvent] will also be valid.

For Leopard (and higher) linked applications, the following drag and drop delegate method will get called only when the dragOperation or drop location changes:
- (NSDragOperation)outlineView:(NSOutlineView *)outlineView
validateDrop:(id <NSDraggingInfo>)info
proposedItem:(id)item
proposedChildIndex:(NSInteger)index;
Prior to Leopard, it would get called constantly, which is not needed.

NSTableView/NSOutlineView - Type to Select

NSTableView and NSOutlineView now support type to select (also known as incremental searching). See the header for the new delegate methods.

NSTableView/NSOutlineView - Disabled state

For applications linked on Leopard, NSTableView and NSOutlineView now properly supports [NSControl isEnabled] and [NSControl setEnabled:(BOOL)flag].

A disabled NSTableView will:
- Refuse first responder status
- Not do any tracking in mouseDown
- Not allow editing of any columns
- Disable selection of rows and columns
- Disable draggging of rows and columns
- Not allow reordering of rows or columns
- Call [NSCell setEnabled:NO] for each cell that is being drawn
- Additionally, NSTextFieldCell's will be drawn with a disabled text color
- Draw the header view with a disabled text color

Setting an NSTableView/NSOutlineView to be enabled or disabled will walk all of the NSTableColumns enable or disable the dataCell and headerCell of that NSTableColumn. You can override the enabled/disabled state of cells in the willDisplayCell delegate method.

NSTableView/NSOutlineView - Cell Hit Testing, Drag and Drop, and Cell Editing

NSTableView now uses the new NSCell hit testing API to perform certain actions. Custom NSCell subclasses in applications that link on or after Leopard should properly implement -hitTestForEvent:inRect:ofView:; see NSCell.h for more information.

NSTableView performs hit testing in the cells to do the following actions:
- Drag and Drop: NSTableView calls hitTestForEvent:inRect:ofView in canDragRowsWithIndexes:atPoint. If the hit cell returns NSCellHitTrackableArea, the particular row will be tracked instead of dragged.
- Cell Editing: When NSTableView recieves a mouse down, single-click editing of text (like Finder) will happen if there is only one row selected, and the cell returns NSCellHitEditableTextArea.

See the DragNDropOutlineView demo application for an example of how to properly implement the NSCell methods.

NSTableView/NSOutlineView - Single click to edit

NSTableView and NSOutlineView now behave like Finder and allow a single click to put it into edit mode. This is done by calling -hitTestForEvent:inRect:ofView: and checking if the cell returns NSCellHitEditableTextArea. This allows you to set a doubleAction and perform some different task when the doubleAction is invoked (for instance, Finder opens files on a double click, and edits via a single click). If the doubleAction is not set, editing is still allowed via a double click.

NSTableView/NSOutlineView - Contextual menu support

NSTableView and NSOutlineView now have better contextual menu support. Please see the DragNDropOutlineView demo application for an example of how to properly do contextual menus with a TableView.

The key thing to note is that clickedRow and clickedColumn will now both be valid when a contextual menu is popped up. In addition, one can dynamically set the popup menu for a particular cell/column in the delegate method willDisplayCell:. NSTableView handles this by properly overriding menuForEvent:, setting the clickedRow/clickedColumn, and calling [NSCell menuForEvent:inRect:ofView] to find the correct menu. If no menu was returned, the menu for the NSTableView will be used. If one right clicks on a selection of items, all the items are highlighted. One should check to see if clickedRow is one of the selected rows, and if it is then do the menu operation on all the selected rows. The clickedRow and clickedColumn properties will still be valid when the action is sent from the NSMenuItem.

NSTableView/NSOutlineView - rowHeight

For applications linked on or after Leopard, the default row height for NSTableView's created with [[NSTableView alloc] init] will be set correctly for the initial font used by the default cell inside an NSTableColumn. NSTableView's created in Interface Builder on Tiger and greater already have the rowHeight correctly set for the particular font selected.

NSTableView/NSOutlineView - Full Width cells and group row look

NSTableView and NSOutlineView now have new delegate API to create the "group row" look. See NSTableView.h/NSOutlineView.h and the DragNDropOutlineView demonstration app for an example of how to use the new delegate methods.

tableView:dataCellForTableColumn:row: allows you to easily return a custom cell for any particular row, without having to subclass NSTableColumn. In addition, you can return a cell that will span the entire width of a table view (a "full width" cell).

If you return YES from tableView:isGroupRow: then the "group row" style will be drawn for that row. The "group row" style is dependent on the selectionHighlightStyle, and will draw differently for different styles.

NSTableView/NSOutlineView - Column rects

Since table columns now can be hidden (see below), the columnsInRect: method is being deprecated in favor of one that can return a set of column indexes rather than just a range:
- (NSIndexSet *)columnIndexesInRect:(NSRect)rect;

NSTableView /NSOutlineView - selectionHighlightStyle:

There is a new property called selectionHighlightStyle with the main purpose of allowing the "source list" highlighting style to be automatically adopted with little or no work.

If the style is set to NSTableViewSelectionHighlightStyleSourceList, then it will draw selected items with a "source list" highlighting style. Additionally, setting NSTableViewSelectionHighlightStyleSourceList on an NSOutlineView will also change the following properties to match the HI guidelines: The backgroundColor, indentationPerLevel, rowHeight and intercellSpacing. If you would like to change any of these properties, you must do so after calling [outlineView setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleSourceList]. Additionally, combining "group rows" with the "source list" highlighting style will produce the standard section header look by implementing -outlineView:isGroupItem: and returning YES for the section headers. To not show a disclosure triangle, override -frameOfOutlineCellAtRow: and return an empty rect. You will also want to not allow it to be collapsed by returning NO from the delegate method -outlineView:shouldCollapseItem:. When the disclosure triangle is not shown for a section header, the item will automatically be unindented. When using the "source list" highlighting style, it is recommended that you draw your cells with 16x16px icons.

One additional note: selected items in "source lists" should be bold, and NSTableView will automatically convert an NSString value inside an NSTextFieldCell to be bold; however, this may conflict with formatters with the cell that expect an NSString instead of an NSAttributedString. If editing a cell makes the title draw blank, be sure to examine any formatters attached to the cell.


NSTableColumn

NSTableColumns now have:
- (void)setHidden:(BOOL)hidden;
- (BOOL)isHidden;
Columns which are hidden still exist in the the -[NSTableView tableColumns] array and -[NSTableView numberOfColumns] includes columns which are hidden. Hidden columns are not included in the indexes returned by the new columnIndexesInRect: method.

The state is saved out with the other autosave information if autosaveTableColumns is set to YES.

You can also now set the tooltip for the column header:
- (void)setHeaderToolTip:(NSString *)string;
- (NSString *)headerToolTip;

NSSavePanel/NSOpenPanel

NSSavePanel and NSOpenPanel now support drag and drop reordering and insertion of items in the sidebar. In addition, you can drag and drop any of the files into the sidebar or Finder.

NSSavePanel and NSOpenPanel now support an "icon view" mode. The icon selection allows the user to change icon size and label location.

For a selection of files, cmd-i will show the Finder info panel and cmd-r will reveal the location in Finder.

NSSavePanel and NSOpenPanel can once again show hidden files by setting a user default. For instance you can use 'defaults write -g AppleShowAllFiles 1' to display hidden files in the panels.

In NSSavePanel, Ctrl-Tab will now quickly tab you to the file list from the name editing text. Ctrl-Shift-Tab will take you back to where you were.

NSSavePanel and NSOpenPanel now have advanced search options. Click the plus button located to the right of the search location buttons to customize the search. Searches can now be saved to the sidebar for use in all applications, or just your application. You can also edit existing searches and resave them.

NSOpenPanel now allows you to browse your iLife and related media. The appropriate media items in the sidebar are displayed based on the types passed to the open panel.


NSPathControl, NSPathCell, NSPathComponentCell

AppKit now has a new control that allows you to easily represent a path, be it a file system path, or a virtual path.

NSPathControl supports three styles:
- NSPathStyleStandard, the same style seen in the NSOpenPanel/NSSavePanel/Finder when a search is done and a file is selected.
- NSPathStyleNavigationBar (aka "breadcrumb"), which is similar to what iTunes has in the iTunes Music Store.
- NSPathStylePopUp, a style that only shows the last path component and uses a popup to display the full path and allow the user to choose a new path.

The primary interaction with the control is done via [NSPathControl setURL:url], which is a wrapper around [NSPathCell setURL:url]. The control automatically supports drag and drop, which can be further customized via delegate methods. The cell's properties can easily be modfied via accessor methods. The NSPathCell also works well in an NSTableView/NSOutlineView, however, the automatic animation will not work when the style is set to NSPathStyleStandard or NSPathStyleNavigationBar. Please refer to the corresponding header files for more information.

NSPathCell

When NSPathCell has the style set to NSPathStylePopUp, if it contains 0 pathComponentCells, it will use the placeholderString for the pop up button. Previously, it would not use a pop up button, and would simply draw the string.

When NSPathCell has the style set to NSPathStylePopUp, if the cell has a border (ie: [cell setBordered:YES]), it will draw the "round bezel" border around the pop up button. Previously, it would not ever draw a border.


NSDictionaryController

There is a new controller class: NSDictionaryController. It can be used to edit dictionary contents as key/value pairs in table views, for example. The controller allows to configure "included keys" (keys always visible in the displayed array of key-value pairs, whether present in the content dictionary or not) and "excluded keys" (keys always hidden in the displayed array of key-value pairs). To support localization, dictionary controllers allow to set a localized key dictionary, which can specify a table of display labels for each key (and will typically be read from a string table).

NSDictionaryController offers bindings for the content dictionary as well as the included keys, excluded keys, and localized key dictionary (which means that the object that provides the content dictionary can also provide the included, excluded, and localized keys at the same time, potentially dynamically computed based on the content dictionary).


NSTreeController

NSTreeController now provides better access to the displayed content objects in the form of NSTreeNode objects. NSTreeNode is designed to represent an individual node in a tree data structure. Each NSTreeNode instance wraps a single representedObject and maintains a reference to its parent and child nodes. NSTreeNodes also know where they are relative to the tree's root node. This location information represented by an NSIndexPath and is returned by NSTreeNode's indexPath method.

In Tiger, NSTreeController's arrangedObjects method returned an opaque proxy that developers weren't supposed to use directly. In Leopard, the arrangedObjects method returns a proxy that responds to the NSTreeNode methods
- (NSArray *)childNodes;
and
- (NSTreeNode *)descendantNodeAtIndexPath:(NSIndexPath *)indexPath;
With these two methods, it is now possible to navigate the tree controller's arranged tree.

By using NSTreeNodes to wrap represented objects, an NSOutlineView bound to an NSTreeController can display the same represented object in multiple rows.

When bound to an NSTreeController, NSOutlineView's row items will be NSTreeNodes. This applies to your outline view delegate or datasource - the items passed to your delegate/datasource methods are NSTreeNode instances. The same is true for NSBrowsers bound to an NSTreeController and the browser delegate methods. You can use the node's location (indexPath) in the arranged tree being displayed, or the underlying model object for the node (representedObject) in order to make decisions in delegate code.


Leveraging NSTreeNode, NSTreeController also exposes two new methods for moving nodes from one place to another.
- (void)moveNode:(NSTreeNode *)node toIndexPath:(NSIndexPath *)indexPath;
- (void)moveNodes:(NSArray *)nodes toIndexPath:(NSIndexPath *)startingIndexPath;
When a node is moved from one location to another, its represented objects in the new and old parent will be updated using Key Value Coding and the tree controller's childrenKeyPath. You are encouraged to use these methods to modify relationships in the tree, rather than modify the represented objects directly. This will ensure better selection handling and improve outline view's ability to maintain item "expanded" state.

NSTreeNodes can be used outside of an NSTreeController to maintain an ad hoc tree of objects. When created outside of a tree controller, the tree nodes do not have a concept of a childrenKeyPath and so don't automatically update relationships of their model objects.

NSTreeController selectedObjects accessor not accurate when not deleting objects through NSTreeController remove:

There is a known bug in NSTreeController's selectedObjects accessor that means that under certain circumstances, the contents of selectedObjects does not accurately reflect the controller selection. This can happen when an object is deleted by mutating the relationship of one of the treeController's model objects instead of using the deleteObjectAtArrangedIndexPath: method of the remove: IBAction method. If this bug affects you, a potential workaround is to replace use of code like
[treeController selectedObjects]
with code like
[[treeController selectedNodes] valueForKey:@"representedObject"]
This will produce an array that accurately represents the treeController's selected objects, even if objects are deleted via manipulating model objects' relationship containers.


NSArrayController

NSArrayController now has API to automatically re-sort/filter content arrays when the objects in it change.
- (void)setAutomaticallyRearrangesObjects:(BOOL)flag;    // default: NO
- (BOOL)automaticallyRearrangesObjects;
- (NSArray *)automaticRearragementKeyPaths;
This method returns the array of key paths that trigger automatic rearranging from the sort descriptors and filter predicates; subclasses may override this method to customize the default behavior (for example if additional arrangement criteria are used in custom implementations of -rearrangeObjects).
- (void)didChangeArrangementCriteria;
This method is invoked by the controller itself when any criteria for arranging objects change (sort descriptors or filter predicates) to reset the key paths for automatic rearranging; subclasses should invoke this method if additional arrangement criteria are used in custom implementations of -rearrangeObjects and those criteria change.


NSObjectController setUsesLazyFetching:

NSObjectController and its subclasses, when in entity mode, can now fetch "lazily." With the behaviour enabled, the controller will try to fetch only a small amount of data from available persistent stores. This can provide a huge improvement in memory use when dealing with a lot of data on disk but just a subset of that data needs to be in memory.

When set to use lazy fetching, a controller will fetch objects in batches - default batch size is 96. You can change the default batch size for your application by setting a value for the the user default "com.apple.CocoaBindings.LazyFetchBatchSize". If you have table views bound to an array controller set to use lazy fetching, the size of the controller's batch size will grow as the table views' visible row count grows.

Add, Insert, and Remove operations on a controller that uses lazy fetching behave similarly to the same operations on a regular controller. The difference is that it is faster to sort an arraycontroller using lazy fetching if
- all of the keys in the sortDescriptors array are modeled, non transient properties
- all of the selectors in the sortDescriptors array are compare: or caseInsensitiveCompare:
- there are no changes in the controller's managed object context


KeyValueObserving notifications for IBOutlets during Nib loading

Prior to 10.5, when an outlet instance variable was set on an object during Nib loading, no corresponding KVO notification would be sent. This meant that registered KVO observers and bindings wouldn't be notified that the observed ivar changed. This could lead to bad behaviour or displaying stale data.

For applications linked on or after 10.5, observers will get KVO notifications when the IBOutlet instance variable is set during Nib loading. Observers should expect to get KVO notifications for an observed object before the observed object's awakeFromNib method is called.


NSAccessibility

Cocoa/Carbon Integration

In Leopard, Cocoa accessibility information is now correctly reported for Cocoa windows used in a Carbon application, as well as Cocoa views embedded into Carbon windows via the new Carbon HICocoaView.

Toolbar Accessibility

Image-based toolbar items have always appeared in the accessibility hierarchy as a single AXButton, with the label of the toolbar item serving as the AXTitle of the button. In Leopard, certain configurations of view-based toolbar items will also be represented automatically in the accessibility hierarchy in this manner:
- The item view is an NSButton that reports itself to accessibility as an AXButton.
- The item view is an NSSegmentedControl with a single segment.
- A toolbar item group has an NSSegmentedControl as its view, and has one labeled subitem per segment.

For view-based toolbar items that do not fit into these special cases, the label of the toolbar item will be automatically attached to the item's view as an AXTitleUIElement in Icon & Text display mode, and as the view's AXDescription in Icon Only mode.

New Accessibility Constants

NSAccessibilityGridRole is a role that should be used for user interfaces like thumbnails and media browsers that present a grid of items. The children of a grid are ordered. A grid is like an accessibility list with the addition of three new attributes: NSAccessibilityRowCountAttribute and NSAccessibilityColumnCountAttribute which return the number of rows and columns in the grid, respectively and NSAccessibilityOrderedByRowAttribute which returns a boolean number value indicating whether the children are ordered row major, or column major.

NSAccessibilityTimelineSubrole is a subrole of NSAccessibilitySliderRole and should be used for media timelines, such as QuickTime movie or audio and video playback and editing controls. A timeline can have multiple value indicators as children to represent different markers on the timeline - for instance the current time, an in point, and an out point for video editing. If multiple value indicators are present, each should have an accessibility description.

The optional attribute NSAccessibilityValueDescriptionAttribute should be used when the value of an element does not provide enough information for assistive applications. For instance, the sliders in the Energy Saver preference pane represent values that include "1 minute", "1 hour", "2 hours 20 minutes", and "never." The numeric value of the slider does not convey this information, so the optional value description attribute should be used. The string values of the attribute should be localized, lower case, and as brief as possible to convey the information.

The optional attribute NSAccessibilitySelectedTextRangesAttribute returns an array of ranges of selected text. NSTextView supports selection of multiple ranges of text as well as this new optional attribute. The existing NSAccessibilitySelectedTextRangeAttribute still returns the first selected text range.

NSAccessibilityDisclosureTriangleRole is a new accessibility role for disclosure triangles.


NSColor

Asking for colorWithAlphaComponent: on NSDeviceRGBColorspace and NSDeviceWhiteColorSpace colors would return results in their calibrated counterparts. This has now been fixed.


NSColorSpace

NSColorSpace now has methods to create from and return a CGColorSpace. Note that the method to return a CGColorSpace might return NULL if the NSColorSpace cannot be represented as a CGColorSpace. In addition, creating an NSColorSpace from a CGColorSpace does not guarantee future pointer identity of the CGColorSpace.

NSColorSpace also has methods to return sRGB and Adobe1998 color spaces.

A CMProfileRef leak was fixed in -[NSColorSpace initWithICCProfileData:].


NSColorPanel

NSColorPickingCustom protocol now enables specifying a tooltip for the toolbar button:
- (NSString *)buttonToolTip;
and setting the minimum size for your picker:
- (NSSize)minContentSize;
NSColorPanel will not allow resizing smaller than this size. By default, you will not have to do anything if you properly setup the autosizing attributes in IB for your view.


Services

We now have a number of NSErrors for reporting services errors. Like other NSErrors in NSCocoaErrorDomain, these errors come ready with user-presentable error messages, and for the most part they will automatically be bubbled up to the user via the Cocoa error presentation machinery, so no developer action is needed. The individual error codes can be found in AppKitErrors.h.

The NSUpdateDynamicServices() function is functional in Leopard. When NSUpdateDynamicServices() is called, applications should see updated services immediately, without needing to be quit and relaunched. Services are also updated at login.


NSScroller

To help improve API uniformity, NSScroller's -setFloatValue:knobProportion: method is being deprecated in favor of using the separate -setDoubleValue: and -setKnobProportion: accessors that have been added in Leopard. To maintain binary compatibility, AppKit will continue to invoke overrides of -setFloatValue:knobProportion:. Code that targets Mac OS 10.5 and later should use -setDoubleValue: and -setKnobProportion: instead, and eliminate any overrides of -setFloatValue:knobProportion:. Code that needs to remain compatible with Mac OS 10.4 and earlier should continue to use -setFloatValue:knobProportion:.


NSUserInterfaceValidations

The interface declarations for NSApplication, NSButton, NSDocument, NSDocumentController, NSMatrix, NSMovieView, NSTableView, NSTextField, and NSWindow now correctly show their conformance to the NSUserInterfaceValidations protocol.


NSTabView

Prior to Leopard, an NSTabViewItem added to multiple tab views would produce inconsistencies. For applications built on or after Leopard, tab view items are automatically removed from the old tab view when added to a new one.


NSLevelIndicator behavior changes

Prior to Mac OS X 10.5, NSLevelIndicatorCell ignored its editable flag; all cells were effectively editable. In 10.5 we pay attention to the flag for apps linked on Leopard and later. The default value of -[NSLevelIndicator isEditable] is and has been NO, so it is necessary to explicitly set the flag for cells that should be editable.


NSRulerView

In the past, the method -moveRulerlineFromLocation:toLocation: immediately handled drawing for temporary lines on the ruler which could cause performance degradation when temporary lines were drawn in conjunction with automatic beam sync. Now, the temporary lines are drawn during -drawRect:.

Usage of -moveRulerlineFromLocation:toLocation: remains unchanged with a few caveats. Each new line location is drawn no more than once. There is however now no guarantee that every new line location will be drawn - if a particular location is set to be drawn and then set to be erased before -drawRect: occurs, that location is never drawn. In addition, any subclass that uses the default -moveRulerlineFromLocation:toLocation: but implements -drawRect: will have to override -moveRulerlineFromLocation:toLocation: to handle ruler line drawing in their own -drawRect: method.


NSBrowser

NSBrowser now supports drag and drop. Please see the AppKit example application "SimpleBrowser" for an example of how to use the API and read the comments in NSBrowser.h. The API is very similar to the drag and drop API for NSTableView.


NSTokenField

NSTokenField has been rewritten and numerous bugs were fixed. Tokens now show the pulldown menu icon regardless of selection state. Applications can set the NSTokenAttachmentUsesDynamicPulldownIcon preference setting to preserve the pre-Leopard behavior.


NSGraphicsContext

NSGraphicsContext now has color rendering intent API:
- (NSColorRenderingIntent)colorRenderingIntent;
- (void)setColorRenderingIntent:(NSColorRenderingIntent)renderingIntent;

NSBezierPath

There are now convenience methods for creating rounded rectangular paths:
+ (NSBezierPath *)bezierPathWithRoundedRect:(NSRect)rect xRadius:(CGFloat)xRadius yRadius:(CGFloat)yRadius;
- (void)appendBezierPathWithRoundedRect:(NSRect)rect xRadius:(CGFloat)xRadius yRadius:(CGFloat)yRadius;

-containsPoint: method now follows the winding rule returned from -windingRule.


NSProgressIndicator

NSProgressIndicatorSpinningStyle and determinate progress indicators now render pie-style determinate indicator found in Mail and Xcode. Spinning-style progress indicators now properly use larger images for NSRegularControlSize rendering. Applications dynamically creating progress indicators for 16x16 image now need to explicitly set the control size to NSSmallControlSize.

The threaded animation setting for newly created indicators is on by default now regardless of the style.


NSWorkspace

NSWorkspace method selectFile: inFileViewerRootedAtPath: no longer follows symlinks. It will now show the symlink in the Finder instead of what it points at. If you wish to show the linked file, use -[NSString stringByResolvingSymlinksInPath] to resolve any symlinks before calling the NSWorkspace method.

The setIcon: forFile: options: method on NSWorkspace will set 512x512 icons, unless NSExclude10_4ElementsIconCreationOption is set in options.

The NSWorkspace method getFileSystemForPath: isRemovable: isWritable: isUnmountable: description: type: now returns meaningful values in description: and type:. (Prior to Leopard, these values were always nil.)


NSMovie/NSMovieView in 64-bit

For 64-bit, NSMovie and NSMovieView have been deprecated in favor of QTKit's QTMovie and QTMovieView. However, because NSMovies may exist in archives that may need to be read or written by 64-bit applications, limited functionality has been provided for NSMovie in 64-bit to enable this.

NSMovies can be unarchived in 64-bit as expected, but because of the absence of NSMovieView, they are not useful on their own. To facilitate the transition to QTMovie and QTMovieView, the existing -QTMovie method on NSMovie has been modified to return a reference to a QTMovie object in 64-bit. This QTMovie instance contains the same movie data that the original NSMovie contained.

For backwards compatibility purposes, an NSMovie can be created in 64-bit using the -initWithMovie: method, which has been modified for 64-bit to accept a QTMovie instance. Archives containing these NSMovie objects are backwards compatible with NSMovies in 32-bit.

Please note that NSMovie in 64-bit does not support movies referenced by URLs. -initWithCoder: will properly read archives containing these movies, but will return nil instead of a valid NSMovie object.


TextEdit

The TextEdit application in 10.5 has been changed to use NSDocument. It thus provides many features provided or enabled by NSDocument, such as correct file tracking and autosaving. In addition it continues to be a showcase for the Cocoa text system, and highlights many of its new features. You can find more info in the README file, in /Developer/Examples/AppKit/TextEdit.


"open" tidbit

Thank you for reading this far! If you are a Terminal or command line user, be sure to check out some of the new features in "open". For instance "open -h" will now search and open header files in Xcode (or your default editor for header files).



Notes specific to Mac OS X 10.4

New AppKit features in Tiger

The following are some of the new features in Tiger.


Foundation:

Some of the other new Mac OS X APIs to be aware of:



NSDatePicker and NSDatePickerCell

AppKit has a new date/time control, whose API is declared in NSDatePicker.h and NSDatePickerCell.h. Currently this class pair provides two styles of date/time control: a "text field and stepper" style that is similar to Carbon's familiar "ClockDate" control, and a graphical "clock and calendar" variant like those that appear in the "Date & Time" System Preferences panel.

A date picker's "objectValue" is an NSDate. The "-dateValue/-setDateValue:" accessor pair provides a type-specific equivalent to the inherited "-objectValue/-setObjectValue:" methods.

A date picker additionally has a "mode" attribute and a "timeInterval" attribute that are not currently used. These attributes exist to support the possibility of a "date range" control mode in the future. The time interval is not applicable, and always zero, when the control is in NSSingleDateMode (the only mode supported by the currently supplied control styles). In NSRangeDateMode, it will specify the duration of the range, which extends forward in time from the cell's dateValue.

An instance's "datePickerElements" attribute determines which components of its value it considers to be specified/specifiable. This setting is composed by bitwise-ORing together one or more of the "DatePickerElementFlag" values declared in NSDatePickerCell.h. It influences both display and editing behavior, as appropriate for the style of date control in use.
typedef unsigned int NSDatePickerElementFlags;
enum {
/* Time Elements */
NSHourMinuteDatePickerElementFlag = 0x000c,
NSHourMinuteSecondDatePickerElementFlag = 0x000e,
NSTimeZoneDatePickerElementFlag     = 0x0010,
    /* Date Elements */
NSYearMonthDatePickerElementFlag     = 0x00c0,
NSYearMonthDayDatePickerElementFlag     = 0x00e0,
NSEraDatePickerElementFlag         = 0x0100,
};
For a case where the "time" portion of the date value is not of interest, for example, this could be set to NSYearMonthDayDatePickerElementFlag. NSTimeZoneDatePickerElementFlag and NSEraDatePickerElementFlag have been declared for possible future use, and do not yet have any effect.

A date picker also has a "calendar", "locale", and "timeZone" that influence date display and editing. In Tiger, date picker functionality supports Gregorian format date display and editing only, but the calendar and locale settings will be used to support other calendars and date formats in the future.

A date picker has a "minDate" and a "maxDate" that can be used to impose a simple range constraint on the possible values the date picker can take. (Both default to nil, meaning that the date value is unconstrained.) Clients can impose more sophisticated constraints in addition to this basic range constraint by providing a delegate object that validates proposed changes to the cell's value. A date picker never allows itself to get into a state where its current value does not satisfy the constraints imposed by minDate, maxDate, and the delegate's validation method (if provided). Its -setObjectValue:/-setDateValue: and -setTimeInterval: accessors will likewise constrain their received parameters to valid values.

The signature of the optional delegate method is:
- (void)dateCell:(NSDatePickerCell *)aDatePickerCell
validateProposedDateValue:(NSDate **)proposedDateValue
timeInterval:(NSTimeInterval *)proposedTimeInterval;
If an date picker has a delegate assigned to it, and the delegate responds to this selector, this method will be invoked each time the user attempts to make a change to the date picker's value, giving the delegate the opportunity to approve, modify, or reject the change.

"proposedDateValue" points to the proposed new dateValue. "proposedTimeInterval" points to the proposed new timeInterval, which will always be zero if the cell is not in NSDateRangeMode. Implementors may find it helpful to consult the NSDatePickerCell's current dateValue and timeInterval for comparison, to determine which of these values (potentially one or both) the cell is proposing to change.

On entry to this delegate method, the start and end points of the proposed range are guaranteed to lie between the NSDatePickerCell's minDate and maxDate, and *proposedTimeInterval is guaranteed to be nonnegative. The delegate can leave *proposedDateValue untouched to accept it, or replace it with a pointer to another NSDate instance. (The replacement value should be autoreleased or otherwise not require a subsequent release.) Likewise, this method can leave the proposedTimeInterval untouched to accept it, or replace its value through the provided pointer.


NSTokenField and NSTokenFieldCell (Section updated since WWDC)

There is a new token field control that behaves like the address field in Mail.app. The new widget supports tokenizing based on a character set (comma by default) and on end editing. In addition, we join tokens for multiple selection using a comma if comma is in the tokenizing character set; Otherwise, we join with space. We invoke text completion after a specified delay.

The tokens are draggable. By default, we put the tokens on the pasteboard using the NSStringPboardType (joined in the same way as the multiple token selection).

Use NSControl/NSCell's setObjectValue: method to set the token field's array of represented objects. If the array contains objects other than NSStrings, you must implement the tokenField:displayStringForRepresentedObject: delegate method.

Known NSTokenField Issues:
- NSTokenFieldCell are not fully functional inside of an NSTableView/Matrix.
- NSTokenField's cell must be a subclass of NSTokenField.

Please refer to NSTokenField.h and NSTokenFieldCell.h for the complete API.


NSLevelIndicator/NSLevelIndicatorCell

There is now a level indicator control and corresponding cell class. This control can display one of 4 styles of capacity, ranking, or relevancy. The capacity style can either be continuous or discrete. The ranking appearance is similar to the iTunes 'stars' ranking and the relevancy ranking can be used to display search ranking in a table.

Depending on the style, there is different behaviour. For relevancy and continuous capacity, the bar is drawn to fill the cell frame and the min/max/value can be any value. For the discrete styles for capacity and rating level, all values are rounded to the nearest integer when displaying. For the rating level, the images are not stretched or shrunk. For the the discrete capacity, the cell will stretch each segment the same amount to fill the cell frame as much as possible. -cellSizeForBounds: will reflect this.

If the cell is editable, the value can be changed by having the user track using the mouse or using the up/down or left/right arrows though only the rating one should be used in that manner. Any of the styles can be marked editable or have tick marks though in most cases, it only the ranking style should be editable and the continuous capacity indictor needs tick marks.

By default, the cell image is nil but if -setImage:, it replaces the default stars with the custom image for the NSRatingLevelIndicatorStyle style. Setting the image has no effect on the other styles. The image is lightened for highlighted selection and the dots for empty spots are still drawn. The image is not stretched no space is added between images.

See the cell for descriptions of the control methods:
@interface NSLevelIndicator : NSControl
- (double)minValue;
- (void)setMinValue:(double)minValue;
- (double)maxValue;
- (void)setMaxValue:(double)maxValue;
- (double)warningValue;
- (void)setWarningValue:(double)warningValue;
- (double)criticalValue;
- (void)setCriticalValue:(double)criticalValue;
- (NSTickMarkPosition)tickMarkPosition;
- (void)setTickMarkPosition:(NSTickMarkPosition)position;
- (int)numberOfTickMarks;
- (void)setNumberOfTickMarks:(int)count;
- (int)numberOfMajorTickMarks;
- (void)setNumberOfMajorTickMarks:(int)count;
- (double)tickMarkValueAtIndex:(int)index;
- (NSRect)rectOfTickMarkAtIndex:(int)index;
@end
Here is the cell declaration:
enum {
NSRelevancyLevelIndicatorStyle,
NSContinuousCapacityLevelIndicatorStyle,
NSDiscreteCapacityLevelIndicatorStyle,
NSRatingLevelIndicatorStyle
} NSLevelIndicatorStyle;
@interface NSLevelIndicatorCell : NSActionCell
- (id)initWithLevelIndicatorStyle:(NSLevelIndicatorStyle)levelIndicatorStyle;
Create new cell with indicator style. Default for -init is NSRelevancyLevelIndicatorStyle. Default value and minimum value are 0, default maximum value depends on the style. For continuous styles, the maximum is 100.0. For discrete ones, it's 5.0
- (void)setLevelIndicatorStyle:(NSLevelIndicatorStyle)levelIndicatorStyle;
- (NSLevelIndicatorStyle)levelIndicatorStyle;
Get/set display style. Will not affect values. Setting will notify enclosing control to update.
- (double)minValue;
- (void)setMinValue:(double)minValue;
- (double)maxValue;
- (void)setMaxValue:(double)maxValue;
These are the same method names as NSSlider and set min/max values for ranking. Setting will notify enclosing control to update.
- (double)warningValue;
- (void)setWarningValue:(double)warningValue;
- (double)criticalValue;
- (void)setCriticalValue:(double)criticalValue;
These set and get the 'warning' and 'critical' values where the indicator goes from green to yellow to red. The order of the values determines which side is green and which side is red. If the critical value is greater than the warning value, then the indicator is green below the warning, yellow above that but below the critical, and red above. If the critical value is less than the warning value, the indicator is red when the value is below the critical value, yellow up to the critical value, and then green to the maximum value. If the values are the same, the indicator is always green.
- (void)setTickMarkPosition:(NSTickMarkPosition)position;
- (NSTickMarkPosition)tickMarkPosition;
- (void)setNumberOfTickMarks:(int)count;
- (int)numberOfTickMarks;
- (NSRect)rectOfTickMarkAtIndex:(int)index;
- (double)tickMarkValueAtIndex:(int)index;
These methods for tick marks are identical to the NSSliderCell APIs with the same behaviour. Set the number of ticks to 0 to not have any. Default is 0. An exception is raised if index is out of range. Setting will notify enclosing control to update if necessary.
- (void)setNumberOfMajorTickMarks:(int)count;
- (int)numberOfMajorTickMarks;
We also allow larger or 'major' tick marks. The count must be less than or equal to the number of tick marks. Setting will notify enclosing control to update if necessary. The major tick marks will be drawn in place of the minor ones.


Resolution Independent UI

As an ongoing effort, we're adding "resolution independent UI." This enables users to choose between more detail or larger user interface without actually having to change physical screen resolution.

In the AppKit we intend to concentrate on the "framework scaling" model (as described in the "Resolution Independent UI" release note), which by default causes windows to be scaled. One fundamental change in this mode is that when drawing to the screen, 1 point in the base window coordinate system is no longer necessarily the same as 1 pixel in the backing store of the window. Although we intend much of the support for this mode to be provided by the AppKit, there are some things applications will need to do themselves or watch out for, as outlined below.

For testing purposes developers can change the display resolution using the Quartz Debug application (located in the folder /Developer/Applications/Performance Tools). Note that because the work for supporting resolution independence in both Cocoa and Carbon is ongoing and not yet complete, there are various drawing problems when running with non-integral scale factors in Tiger. This is especially true when Quartz 2D Extreme acceleration is enabled.

Applying the scale factor

Windows are scaled using a transformation on the coordinate system of the top level view (the frameView). The dimensions of the frame of the frameView are equal to the dimensions of the window frame, as in the non-scaled case, but the dimensions of the bounds of the frameView are scaled by dividing the dimensions of the frame by the scaleFactor. For non-integral scaleFactors, the frame is kept integral but the bounds are allowed to have a fractional component. So, for example, a 100x100 window will have a frameView whose bounds is 80x80 for a userSpaceScaleFactor of 1.25. We consider the window frame to be in pixels, and the frameView bounds to be in points. Drawing within the window content is then done in points. Note that this implies that all views within the window are scaled, but we have decided that views whose only scaling is this base scaling for resolution independence purposes will return NO from -isRotatedOrScaledFromBase, so that scrolling, etc. will continue to go through the fast path.

Implications for view positioning and window sizing

Applications must not assume that the window frame and contained view frames use the same coordinate systems. For example, applications that use the window frame to position views will not get correct results. Likewise, applications that compute a change in window frame based on view size (eg. when adding an auxiliary view) will be incorrect. One mechanism for converting between coordinate systems correctly is -[NSView convertRect/Size/Point to/fromView:nil]. Another is -[NSWindow frameRectForContentRect:] and its inverse -[NSWindow contentRectForFrameRect:].

Images

Each imageRep that contains bitmap data indicates its own DPI, since it has both size in points and pixel width and height. An imageRep with 72 DPI has a 1-1 correspondence between points and pixels. An imageRep with 144 DPI has two times more pixels than points in both dimensions. We now create cachedImage reps with the scale factor of the destination window. For a window with a userSpaceScaleFactor of 1.25, a cachedImageRep of 100x100 points would report a size of 100x100, and a pixelWidth and pixelHeight of 125.

Compositing

Historically, compositing has been done in the base coordinate system, regardless of the destination coordinate system. To allow composite: to continue to work in a resolution independent environment, we define the base coordinate system of scaled windows to include the current scale factor.

Example 1 - compositing 72dpi 100x100 source image to view in 1.25x scaled window

A 72dpi 100x100 source image will contain 100x100 pixels. When composited into a 100x100 rect in a view in a scaled window, this image will be scaled to fill 125x125 pixels in the window using the appropriate interpolation algorithm. Any coordinate transforms on the destination view aside from window scaling will be ignored.

Example 2 - compositing 90dpi 100x100 source image to view in 1.25x scaled window

A 90dpi 100x100 source image will contain 125x125 pixels. When composited into a 100x100 rect in a view in a scaled window, this image will exactly fit 125x125 pixels in the window, so no interpolation will be needed. Any coordinate transforms on the destination view aside from window scaling will be ignored.

Example 3 - creating cached image rep from 72dpi 100x100 source image

A 72dpi 100x100 source image will contain 100x100 pixels. The cached image rep will be created with size 100x100, but will hold 125x125 pixels. The source image will be scaled to fit the pixel size of the cached image rep, using the appropriate interpolation. When the cached image rep is later drawn into a scaled window, this will be a 1 to 1 copy from cached image rep pixels to destination window pixels.

Dealing with non-integral view coordinates

In the past, view coordinates have been modified to land on integral boundaries in order to use an exact number of pixels. In a scaled window, any computation to put a view on integral boundaries should be done in the window coordinate system (pixels) then converted to the view coordinate system.

API for "application scaling" mode

The following API allow applications to use their own techniques to achieve resolution independence themselves. One use of this API might be to generate an inverse scaling on the bounds of a view that wants to draw in pixels rather than points.

This is the default scaling from user space to device space on the given screen:
@interface NSScreen : NSObject
...
- (float)userSpaceScaleFactor
...
@end
Since the scale factor gets applied to individual windows, we also provide a method to ask a window for its scaling. By default, this scale factor will be equal to the scale factor of the NSScreen on which the window was created, or the highest scale factor of the available NSScreens if no screen was specified at creation time. (Note that for the foreseeable future the scale factor of all NSScreens will be equal at any given time):
@interface NSWindow : NSResponder
...
- (float)userSpaceScaleFactor
...
@end
It might also be necessary to allow creation of windows without a scale factor, especially for custom windows. You can create an unscaled window by specifying a styleMask of NSUnscaledWindowMask at creation time.

An unscaled window would then return 1.0 for -userSpaceScaleFactor.

Impact on existing API

Both NSWindow and NSScreen define a -deviceDescription method, This method returns an NSDictionary containing a NSDeviceResolution key. NSDeviceResolution has historically contained an NSSize of (72.0, 72.0). On a scaled system, NSDeviceResolution will contain an NSSize of (72.0*userSpaceScaleFactor, 72.0*userSpaceScaleFactor).


NSAnimation

This base class implements timing for animation in Cocoa. There is one subclass available for view animation. The animation can run in the main event thread in blocking mode (i.e. not returning until done), in non-blocking mode so that events are still accepted and in an separate private thread.
typedef enum {
NSAnimationEaseInOut, /* s-curve, default */
NSAnimationEaseIn,
NSAnimationEaseOut,
NSAnimationLinear
} NSAnimationCurve;
typedef enum {
NSAnimationBlocking,
NSAnimationNonblocking,
NSAnimationNonblockingThreaded
} NSAnimationBlockingMode;
typedef float NSAnimationProgress;                      // value in range 0..1
extern NSString *NSAnimationProgressMarkNotification;   // has single entry in user info dictionary
extern NSString *NSAnimationProgressMark; // NSNumber(float) with NSAnimationProgress
@interface NSAnimation
- (id)initWithDuration:(NSTimeInterval)duration animationCurve:(NSAnimationCurve)animationCurve;
- (void)startAnimation;
- (void)stopAnimation;
- (BOOL)isAnimating;
Starts and stops the animation. Doesn't reset the progress when stopped. If at a progress of 1.0, calling -startAnimation starts again at progress 0.0. You can play an animation with no view, target or action. If the mode is set to NSAnimationBlocking, then -startAnimation only returns after the animation has run. The delegate can still stop the animation while running if necessary. When -startAnimation is called, the animation retains itself and then is autoreleased on -stopAnimation.
- (NSAnimationProgress)currentProgress;
- (void)setCurrentProgress:(NSAnimationProgress)progress;
Set/get the current progress (values 0.0...1.0). Can change while running. Out of range values are pinned to 0.0 or 1.0. The -setCurrentProgress method is called while playing to change the progress for the next frame. Subclasses should override to get the value and do their action. This action may be in a secondary thread if requested.
- (void)setDuration:(NSTimeInterval)duration;
- (NSTimeInterval)duration;
Set/get the duration of the effect. Duration is in seconds. Can change while running. Negative values raise an exception. If the duration set is past the current time and the animation is playing, the animation is ended.
- (NSAnimationBlockingMode)animationBlockingMode;
- (void)setAnimationBlockingMode:(NSAnimationBlockingMode)animationBlockingMode;
Set/get mode for running animation. Will take effect the next time the animation is started. Has no effect if animation already running. Default is NSAnimationBlocking. If set to NSAnimationBlocking, animation is run in main thread in custom run loop mode blocking UI. If animation is run NSAnimationNonblocking then animation is run in main thread in the common run loop modes or the ones specified in -runLoopModesForAnimating. NSAnimationNonblockingThreaded spawns a new thread that runs the animation.
- (void)setFrameRate:(float)framesPerSecond;
- (float)frameRate;
Set/get the frame rate (updates/second) of the effect. The frame rate is not guaranteed. Can be changed while running and will be used at the next frame. Value must be positive. A value of 0.0 means as fast as possible (currently limited to 30 fps). Negative values raise an exception.
- (void)setAnimationCurve:(NSAnimationCurve)curve;
- (NSAnimationCurve)animationCurve;
Set/get the animation curve. Predefined curves are linear, ease in (slow down as we reach end), ease out (slowly speed up start), and ease in/outS-curve. This setting is ignored if the delegate implements -animation:valueForProgress:. Invalid values raise an exception.
- (float)currentValue;
This is the current value of the effect based on the current progress. It is derived from the animation curve or from the delegate. This is a read-only setting. A subclass can override this method to provide a custom curve. The current value can be less than 0.0 or larger than 1.0. For example, by allowing the size to be greater then 1.0, one could do a 'rubber effect' where temporarily, the size of the view is larger than the final.
- (void)setDelegate:(id)delegate;
- (id)delegate;
Set/get the delegate. This is a weak reference - the delegate is not retained.
- (NSArray *)progressMarks;
- (void)setProgressMarks:(NSArray *)progressMarks;
These set/get all the progress marks at once. Array contains a list of NSNumbers containing NSAnimationProgress (floats). If there are no progress marks set, -progressMarks returns an empty array. Passing in nil to -setProgressMarks: will clear all progress marks..
- (void)addProgressMark:(NSAnimationProgress)progress;
- (void)removeProgressMark:(NSAnimationProgress)progress;
These set and clear 'progress marks'. These are used to notify the delegate or post a notification that the particular progress point has been reached. They can be used to synchronize animations (e.g. starting a new animation when the first one has reached the half-way point.) The notifications are only sent if the animation is playing. They can be called during playing of the animation. The notification is sent as soon as the progress point is passed so the actual currentProgress may be different from the requsted mark point. Valid intervals are from 0.0 to 1.0. Both 0.0 and 1.0 marks will always be send. Multiple marks may be sent during a single frame if the times are close enough together..
- (void)startWhenAnimation:(NSAnimation *)animation reachesProgress:(NSAnimationProgress)startProgress;
- (void)stopWhenAnimation:(NSAnimation *)animation reachesProgress:(NSAnimationProgress)stopProgress;
- (void)clearStartAnimation;
- (void)clearStopAnimation;
This links another animation to this one. When the linked animation reaches a certain progress point, the animation starts and/or stops. You can only have one animation set as a start animation and one set as a stop animation. Setting a new will will clear out the old one. You can also clear out the old one using -clearStartAnimation or -clearStopAnimation.
- (NSArray *)runLoopModesForAnimating;
By default, it returns nil. Custom subclass can override to return specific list run loop modes to run animation timer in. If it returns nil, the animation is run in any of default, modal, and event tracking modes. Ignored if animation mode isn't set to NSAnimationNonblocking.

Delegate Methods
- (BOOL)animationShouldStart:(NSAnimation *)animation;
- (void)animationDidStop:(NSAnimation *)animation;
- (void)animationDidEnd:(NSAnimation *)animation;
Called on start/stop animation and when animation reaches a progress vallue of 1.0. -animationShouldStart: can return NO to cancel the start. -animationDidStop: is called when the animation is explicitly stopped. -animationDidEnd: is called when it ends by reaching a progress value of 1.0. Only called if actual change occurs (i.e. won't call -animationShouldStart: if already playing)
- (float)animation:(NSAnimation *)animation valueForProgress:(NSAnimationProgress)progress;
Delegate can provide custom curve values. progress will always be from 0.0 to 1.0.
- (void)animation:(NSAnimation *)animation didReachProgressMark:(NSAnimationProgress)progress;
Called when the animation reaches a previously marked progress value. The actual current progress may be past the one passed in. Can also use the NSAnimationProgressMarkNotification notification.


NSViewAnimation

This is the only public subclass of NSAnimation. It takes an array of dictionaries that are copied and parses the dictionary. The dictionary contains a target which is required and which can be a window or view. It takes an optional start and/or end frame which if not defined uses the current frame when the animation starts. It can optionally take an effect which will, fade in or out the view or window. If the target is a view and the effect is to fade out or the end frame is empty, the view is hidden at the end. If the effect is to fade in and the end frame is non-empty and the view starts hidden, it is unhidden at the end. If there is no effect, the view frame is changed while animating. If the target is a window, the window is similarly ordered in or out. The animation is non-blocking by default, a duration of 0.5 seconds and the ease in-out curve.
APPKIT_EXTERN NSString *NSViewAnimationTargetKey;       // NSWindow* or NSView* (required)
APPKIT_EXTERN NSString *NSViewAnimationStartFrameKey; // NSValue*(NSRect) (optional)
APPKIT_EXTERN NSString *NSViewAnimationEndFrameKey; // NSValue*(NSRect) (optional)
APPKIT_EXTERN NSString *NSViewAnimationEffectKey; // NSString*(effect strings)(optional)
APPKIT_EXTERN NSString *NSViewAnimationFadeInEffect;
APPKIT_EXTERN NSString *NSViewAnimationFadeOutEffect;
@interface NSViewAnimation
- (id)initWithViewAnimations:(NSArray *)viewAnimations;
- (NSArray *)viewAnimations;
- (void)setViewAnimations:(NSArray *)viewAnimations;
@end

AppKit Extensions to support use of CoreImage API (Section added since WWDC)

The following API has been added to facilitate more convenient use of CoreImage functionality by Cocoa applications.

There is a new NSImageRep subclass called NSCIImageRep, which makes it possible to construct an NSImage that references a CIImage, as in the following code sample:
CIImage ciImage = [aCIFilter valueForKey:@"outputImage"];
CGRect extent = [ciImage extent];
/* Be careful here. A CIImage can have infinite extent. The following is OK only if you know your CIImage is of finite extent. */
NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize(extent.size.width, extent.size.height)];
NSCIImageRep *ciImageRep = [NSCIImageRep imageRepWithCIImage:outputImage];
[image addRepresentation:ciImageRep];
The resultant NSImage should be usable in any context where an NSImage is called for. CoreImage will automatically render the result on demand. Note that CIImage instances are immutable, so when a change is made to a CIFilter parameter that affects the filter's output image, a new "outputImage" must be requested from the filter, and a new NSCIImageRep constructed from it.

NSCIImageRep.h also adds three new methods to CIImage via a category. The first enables clients to create a CIImage from an NSBitmapImageRep:
@interface CIImage (NSAppKitAdditions)
- (id)initWithBitmapImageRep:(NSBitmapImageRep *)bitmapImageRep;
The remaining two provide a convenient means to render all or part of a CIImage into the current NSGraphicsContext. They behave identically to the like methods in NSImage:
- (void)drawInRect:(NSRect)rect fromRect:(NSRect)fromRect operation:(NSCompositingOperation)op fraction:(float)delta;
- (void)drawAtPoint:(NSPoint)point fromRect:(NSRect)fromRect operation:(NSCompositingOperation)op fraction:(float)delta;
@end
NSGraphicsContext has a new method, -CIContext, that returns an associated CIContext that can be used to render into the NSGraphicsContext. The CIContext is created on demand, and remains in existence for the lifetime of its owning NSGraphicsContext. If desired, a CIContext can be asked to free the resources it holds by sending it a -reclaimResources or -clearCaches message.

New methods have been added to facilitate conversion between NSColor and CIColor types (the declarations are in NSColor.h):
@interface NSColor (NSQuartzCoreAdditions)
+ (NSColor *)colorWithCIColor:(CIColor *)color;
@end
@interface CIColor (NSAppKitAdditions)
- (id)initWithColor:(NSColor *)color;
@end
An NSColor can be converted to a CIColor as long as it isn't a pattern color. A CIColor can always be converted to an NSColor.

See the Core Image documentation for additional information on the use of Core Image functionality.


New NSResponder-Based Error Presentation (Section added since WWDC)

A new mechanism has been added to Cocoa to enable user-friendly error alerts that are informative, take proper advantage of sheets, and are easily customizable. Cocoa affords customization by publishing an overridable NSResponder method and an NSApplication delegate method that can be implemented. Such a method will typically examine the passed-in NSError object and, using the NSError's domain and code to determine what kind of error is to be presented, return a different NSError object if appropriate. NSError's existing underlyingError attribute makes it feasible to replace one NSError with another that is more presentable without destroying any information about the original detected cause of the problem.

Sometimes it is appropriate to present the user with error recovery options, and act accordingly after the user has chosen one of the options. For example, NSDocument can, when a document being saved is found to be locked, offer to override the lock and save anyway (it doesn't though, in Tiger). Cocoa supports this sort of functionality with the localizedRecoverySuggestion, localizedRecoveryOptions and recoveryAttempter attributes that have been added to Foundation's NSError class and that are honored by various AppKit classes that deal in NSErrors. See the "NSError" section of the Foundation release notes.

Three new methods have been added to the NSResponder class:
- (void)presentError:(NSError *)error modalForWindow:(NSWindow *)window
delegate:(id)delegate didPresentSelector:(SEL)didPresentSelector contextInfo:(void *)contextInfo;
Present an error alert to the user, as a document-modal panel. When the user has dismissed the alert and any recovery possible for the error and chosen by the user has been attempted, send the selected message to the specified delegate. The method selected by didPresentSelector must have the same signature as:
- (void)didPresentErrorWithRecovery:(BOOL)didRecover contextInfo:(void *)contextInfo;
The default implementation of this method always invokes [self willPresentError:error] to give subclassers an opportunity to customize error presentation. It then forwards the message, passing the customized error, to the next responder or, if there is no next responder, NSApp. NSApplication's override of this method invokes [[NSAlert alertWithError:theErrorToPresent] beginSheetModalForWindow:window modalDelegate:self didEndSelector:selectorForAPrivateMethod contextInfo:privateContextInfo]. When the user has dismissed the alert, the error's recovery attempter is sent an -attemptRecoveryFromError:optionIndex:delegate:didRecoverSelector:contextInfo: message, if the error had recovery options and a recovery delegate.

Errors for which ([[error domain] isEqualToString:NSCocoaErrorDomain] && [error code]==NSUserCancelledError) are a special case, because they do not actually represent errors and should not be presented as such to the user. NSApplication's override of this method does not present an alert to the user for these kinds of errors. Instead it merely invokes the delegate specifying didRecover==NO.

Between the responder chain in a typical application and various overrides of this method in AppKit classes, objects are given the opportunity to present errors in orders like these:

For windows owned by documents:
view -> superviews -> window -> window controller -> document -> document controller -> application

For windows that have window controllers but aren't associated with documents:
view -> superviews -> window -> window controller -> application

For windows that have no window controller at all:
view -> superviews -> window -> application

You can invoke this method to present error alert sheets. For example, Cocoa's own -[NSDocument saveToURL:ofType:forSaveOperation:delegate:didSaveSelector:contextInfo:] invokes this method when it's just invoked -saveToURL:ofType:forSaveOperation:error: and that method has returned NO.

You probably shouldn't override this method, because you have no way of reliably predicting whether this method vs. -presentError will be invoked for any particular error. You should instead override the -willPresentError: method described below.
- (BOOL)presentError:(NSError *)error;
Present an error alert to the user, as an application-modal panel, and return YES if error recovery was done, NO otherwise. This method behaves much like the previous one except it does not return until the user has dismissed the alert and, if the error had recovery options and a recovery delegate, the error's recovery delegate has been sent an -attemptRecoveryFromError:optionIndex: message.

You can invoke this method to present error alert dialog boxes. For example, Cocoa's own [NSDocumentController openDocument:] invokes this method when it's just invoked -openDocumentWithContentsOfURL:display:error: and that method has returned nil.

You probably shouldn't override this method, because you have no way of reliably predicting whether this method vs. -presentError:modalForWindow:delegate:didPresentSelector:contextInfo: will be invoked for any particular error. You should instead override the -willPresentError: method described below.
- (NSError *)willPresentError:(NSError *)error;
Given that the receiver is about to present an error (perhaps by just forwarding it to the next responder), return the error that should actually be presented. The default implementation of this method merely returns the passed-in error.

You can override this method to customize the presentation of errors by examining the passed-in error and if, for example, its localized description or recovery information is unsuitably generic, returning a more specific one. When you override this method always check the NSError's domain and code to discriminate between errors whose presentation you want to customize and those you don't. For those you don't just return [super willPresentError:error]. Don't make decisions based on the NSError's localized description, recovery suggestion, or recovery options because it's usually not a good idea to try to parse localized text.

NSDocument and NSDocumentController are not subclasses of NSResponder, and documents and the shared document controller are not in the responder chain, for historical reasons. NSDocument and NSDocumentController nonetheless implement the three new methods described above, and error presentation messages are by default forwarded as if documents and the shared document controller are in the responder chain. (NSWindowController also overrides the error presentation methods to help make this happen.)

In many applications it will be appropriate to override -willPresentError: in a subclass of NSWindowController, NSDocument, or NSDocumentController, but in some applications it will be easiest to customize some error presentation on a per-application basis. So that you don't have to subclass NSApplication to do so, a new application delegate method has been added:
- (NSError *)application:(NSApplication *)application willPresentError:(NSError *)error;
Given that the application object is about to present an error, return the error that should actually be presented.

You can implement this delegate method to customize the presentation of any error presented by your application, as long as no code in your application overrides -presentError:modalForWindow:delegate:didPresentSelector:contextInfo: or -presentError: in a way that prevent errors from being passed down to the application object. Your implementation of this delegate method should follow the advice given for overriding of -[NSResponder willPresentError:], except that it should just return the passed-in error instead of [super willPresentError:error].


New Error Presentation Method in NSAlert (Section added since WWDC)

We may in the future add to NSError still more attributes that are meant to contribute to the presentation of the error to the user. In that case it would be ideal if NSErrors carrying such attributes were presented properly, so a new method has been added to NSAlert to reduce the need for NSErrors to be picked apart by code that is naive of future NSError additions:
+ (NSAlert *)alertWithError:(NSError *)error;
Given an NSError, create an NSAlert that can be used to present the error to the user. The error's localized description, recovery suggestion, and recovery options will be used to set the alert's message text, informative text, and button titles, respectively.


NSDocument/NSDocumentController Error Handling (Section updated since WWDC)

In previous releases of Mac OS X Cocoa's NSDocument and NSDocumentController classes presented alerts that weren't informative, and it was very difficult to customize them. Both classes have been updated to take advantage of the NSError class that was added to Cocoa in Mac OS 10.3. Methods have been added to both classes, and methods have been deprecated. The new methods all consistently deal in NSURLs, replacing the melange of paths and URLs that previously existed.


New NSDocument Methods for Error Handling (Section updated since WWDC)

- (id)initWithContentsOfURL:(NSURL *)absoluteURL ofType:(NSString *)typeName error:(NSError **)outError;
Initialize a document located by a URL, of a specified type, and return it if successful. If not successful, return nil after setting *outError to an NSError that encapsulates the reason why the document could not be initialized. The default implementation of this method invokes [self init], [self readFromURL:absoluteURL ofType:typeName error:outError], [self setFileURL:absoluteURL], [self setFileType:typeName], and [self setFileModificationDate:theModificationDate].

This method replaces -initWithContentsOfFile:ofType: and -initWithContentsOfURL:ofType:, which are now deprecated. For backward binary compatibility -initWithContentsOfFile:ofType: is still invoked when appropriate if it is overridden. -initWithContentsOfURL:ofType: is never invoked from anywhere within Cocoa, as in Mac OS 10.3 and earlier.
- (BOOL)revertToContentsOfURL:(NSURL *)absoluteURL ofType:(NSString *)typeName error:(NSError **)outError;
Discard all unsaved document modifications and replace the document's contents by reading a file or file package located by a URL, of a specified type, and return YES if successful. If not successful, return NO after setting *outError to an NSError that encapsulates the reason why the document could not be reverted. The default implementation of this method invokes [self readFromURL:absoluteURL ofType:typeName error:outError], [self setFileModificationDate:theModificationDate], [self updateChangeCount:NSChangeCleared], and, if the document has an undo manager, [[self undoManager] removeAllActions]. It also deletes autosaved contents files when they have become obsolete.

This method replaces -revertToSavedFromFile:ofType: and -revertToSavedFromURL:ofType: which are now deprecated. For backward binary compatibility, -revertToSavedFromFile:ofType is still invoked when appropriate if overridden. -revertToSavedFromURL:ofType: is never invoked from anywhere within Cocoa, as in Mac OS 10.3 and earlier.
- (BOOL)readFromURL:(NSURL *)absoluteURL ofType:(NSString *)typeName error:(NSError **)outError;
- (BOOL)readFromFileWrapper:(NSFileWrapper *)fileWrapper ofType:(NSString *)typeName error:(NSError **)outError;
- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError;
- (BOOL)writeToURL:(NSURL *)absoluteURL ofType:(NSString *)typeName error:(NSError **)outError;
- (NSFileWrapper *)fileWrapperOfType:(NSString *)typeName error:(NSError **)outError;
- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError;
Methods that are meant to be optionally overridden in the same manner as the non-NSError-returning methods that they replace. See the comments in <AppKit/NSDocument.h> for details.

The replaced methods are -readFromFile:ofType:, -loadFileWrapperRepresentation:ofType:, -loadDataRepresentation:ofType:, -writeToFile:ofType:, -fileWrapperRepresentationOfType:, and -dataRepresentationOfType:. They are all now deprecated. For backward binary compatibility, the old methods are still invoked when appropriate if overridden. Also deprecated are -readFromURL:ofType: and -writeToURL:ofType:, which are never invoked from anywhere within Cocoa, as in Mac OS 10.3 and earlier.
- (BOOL)writeSafelyToURL:(NSURL *)absoluteURL ofType:(NSString *)typeName
forSaveOperation:(NSSaveOperationType)saveOperation
error:(NSError **)outError;
- (BOOL)writeToURL:(NSURL *)absoluteURL ofType:(NSString *)typeName
forSaveOperation:(NSSaveOperationType)saveOperation
originalContentsURL:(NSURL *)absoluteOriginalContentsURL
error:(NSError **)outError;
- (NSDictionary *)fileAttributesToWriteToURL:(NSURL *)absoluteURL ofType:(NSString *)typeName
forSaveOperation:(NSSaveOperationType)saveOperation
originalContentsURL:(NSURL *)absoluteOriginalContentsURL
error:(NSError **)outError;
More methods that are meant to be optionally overridden in the same manner as the non-NSError-returning methods that they replace. See the comments in <AppKit/NSDocument.h> for details.

The replaced methods are -writeWithBackupToFile:ofType:saveOperation:, -writeToFile:ofType:originalFile:saveOperation:, and -fileAttributesToWriteToFile:ofType:saveOperation:. They are all now deprecated. For backward binary compatibility, the old methods are still invoked when appropriate if overridden.
- (void)setFileURL:(NSURL *)absoluteURL;
- (NSURL *)fileURL;
Accessors for the location of the document's on-disk representation. The set method doesn't actually rename the document, it's just for recording the document's location during initial opening or saving. The default implementation of -setFileURL: just records the URL so that the default implementation of -fileURL can return it. The default implementation of -fileURL returns whatever was stored by a previous invocation of the default implementation of -setFileURL:.

As part of the parallel effort to use NSURLs consistently, these methods replace -setFileName: and -fileName, which are now deprecated. For backward binary compatibility the old methods are still invoked when appropriate if overridden.
- (void)saveToURL:(NSURL *)absoluteURL ofType:(NSString *)typeName
forSaveOperation:(NSSaveOperationType)saveOperation
delegate:(id)delegate didSaveSelector:(SEL)didSaveSelector contextInfo:(void *)contextInfo;
Save the contents of the document to a file or file package located by a URL, formatted to a specified type, for a particular kind of save operation. When saving is completed, regardless of success or failure, send the message selected by didSaveSelector to the delegate, with the contextInfo as the last argument. The method selected by didSaveSelector must have the same signature as:
- (void)document:(NSDocument *)document didSave:(BOOL)didSaveSuccessfully contextInfo:(void *)contextInfo;
The default implementation of this method first makes sure that any editor registered using Cocoa Bindings' NSEditorRegistration informal protocol has committed its changes (except for autosave operations), then invokes [self saveToURL:absoluteURL ofType:typeName forSaveOperation:saveOperation error:&anError] and, if NO is returned, presents the error to the user in a document-modal panel before messaging the delegate.

As part of the parallel effort to use NSURLs consistently, this method replaces -saveToFile:saveOperation:delegate:didSaveSelector:contextInfo:, which is now deprecated. For backward binary compatibility the old method is still invoked when appropriate if overridden.


New NSDocumentController Methods for Error Handling (Section updated since WWDC)

- (id)openUntitledDocumentAndDisplay:(BOOL)displayDocument error:(NSError **)outError;
- (id)makeUntitledDocumentOfType:(NSString *)typeName error:(NSError **)outError;
- (id)openDocumentWithContentsOfURL:(NSURL *)absoluteURL display:(BOOL)displayDocument error:(NSError **)outError;
- (id)makeDocumentWithContentsOfURL:(NSURL *)absoluteURL ofType:(NSString *)typeName error:(NSError **)outError;
Methods that are meant to be optionally overridden in the same manner as the non-NSError-returning methods that they replace. See the comments in <AppKit/NSDocumentController.h> for details.

The replaced methods are -openUntitledDocumentOfType:display:, -makeUntitledDocumentOfType:, -openDocumentWithContentsOfFile:display:, and makeDocumentWithContentsOfFile:ofType:. They are all now deprecated. For backward binary compatibility, the old methods are still invoked when appropriate if overridden. Also deprecated are -openDocumentWithContentsOfURL:display: and -makeDocumentWithContentsOfURL:ofType:, which are never invoked from anywhere within Cocoa, as in Mac OS 10.3 and earlier.
- (id)documentForURL:(NSURL *)absoluteURL;
Given a URL, return the open document whose file or file package is located by the URL, or nil if there is no such open document. The default implementation of this method queries each open document to find one whose URL matches, and returns the first one whose URL does match.

As part of the parallel effort to use NSURLs consistently, this method replaces -documentForFileName:, which is now deprecated. For backward binary compatibility the old method is still invoked when appropriate if overridden.

-fileNamesFromRunningOpenPanel: is also deprecated. It is no longer invoked by -openDocument: unless it is overridden. The existing -URLsFromRunningOpenPanel: method is now used instead.

Finally, -setShouldCreateUI: and -shouldCreateUI are deprecated, because as used by NSDocumentController in the past they are not useful. -shouldCreateUI is still invoked by the also-deprecated -openUntitledDocumentOfType:display:, -openDocumentWithContentsOfFile:display:, and -openDocumentWithContentsOfURL:display: methods, and also the new -openUntitledDocumentAndDisplay:error: and -openDocumentWithContentsOfURL: display:error: methods, but only for backward compatibility. If your NSDocument subclass is sending itself a -makeWindowControllers message during initialization, and you're using -setShouldCreateUI: to keep NSDocumentController from sending another -makeWindowControllers message, you should considering fixing your NSDocument subclass, because NSDocuments should never need to invoke -makeWindowControllers during initialization.


Use of NSSaveAsOperation Instead of NSSaveOperation in NSDocument

-saveDocumentWithDelegate:didSaveSelector:contextInfo: now invokes -runModalSavePanelForSaveOperation:delegate:didSaveSelector:contextInfo: with NSSaveAsOperation instead of NSSaveOperation when a save panel is going to be presented. Checking saveOperation==NSSaveOperation without also checking [self fileName] or [self fileURL] is now valid, for apps that require Tiger.


Change to NSDocument's Standard Save Panel Accessory View

The File Format popup in the standard save panel accessory view installed by NSDocument no longer includes export-only file type items for NSSaveOperation and NSSaveAsOperation. Those items were always disabled, but because the user could not possibly cause them to become enabled by doing something in the save panel it was not appropriate to include them.


Change to NSDocumentController's Presentation of Document Opening Errors

In previous releases of Mac OS X NSDocumentController would present an error alert if a document selected by the user with the open panel could not be opened, but it would not present the same alert when the document opening was attempted as a result of the user double-clicking on the document's icon in the Finder, or dragging of the document's icon onto the application's icon. This has been fixed. NSDocumentController now consistently presents an error alert whenever document opening fails. For backward binary compatibility, NSDocumentController does not do this in applications linked against Mac OS 10.3 or earlier, because several applications have worked around the problem by presenting error alerts of their own (and two error alerts are not better than one).


New NSDocument Initializer Just For New Documents (Section updated since WWDC)

In previous releases of Mac OS X there was no NSDocument initializer that would be invoked when a new document was created but not when a document was being opened. Such an initializer has been added:
- (id)initWithType:(NSString *)typeName error:(NSError **)outError;
Initialize a new empty document of a specified type, and return it if successful. If not successful, return nil after setting *outError to an NSError that encapsulates the reason why the document could not be initialized. The default implementation of this method just invokes [self init] and [self setFileType:typeName].

You can override this method to perform initialization that must be done when creating new documents but should not be done when opening existing documents. Your override should typically invoke super, or at least it must invoke -init, NSDocument's designated initializer, to initialize NSDocument's private instance variables.


New NSDocument Methods for File Modification Dates (Section updated since WWDC)

New NSDocument methods have been added to track the modification date of the document's file on disk:
- (void)setFileModificationDate:(NSDate *)modificationDate;
- (NSDate *)fileModificationDate;
The method -fileModificationDate returns the last known modification date of the document's on-disk representation. -setFileModificationDate: is invoked by the default implementations of -initWithContentsOfURL:ofType:error:, -initForURL:withContentsOfURL:ofType:error:, -revertToContentsOfURL:ofType:error:, and -saveToURL:ofType:forSaveOperation:error:. In a future release -saveDocumentWithDelegate:didSaveSelector:contextInfo: may test the file modification date and warn the user when they may be about to overwrite modifications by something other than the current application.


New NSDocument Method for All Document Saving

A new method has been added to NSDocument so that you can override it to do things before and after any save operation:
- (BOOL)saveToURL:(NSURL *)absoluteURL ofType:(NSString *)typeName
forSaveOperation:(NSSaveOperationType)saveOperation error:(NSError **)outError;
Save the contents of the document to a file or file package located by a URL, formatted to a specified type, for a particular kind of save operation, and return YES if successful. If not successful, return NO after setting *outError to an NSError that encapsulates the reason why the document could not be saved.

The default implementation of this method invokes [self writeSafelyToURL:absoluteURL ofType:typeName forSaveOperation:saveOperation error:outError]. If that returns YES, it also invokes some combination of -setFileModificationDate:, -setFileType:, -setFileURL:, -updateChangeCount:, and -setAutosavedContentsFileURL:, as appropriate for the kind of save operation. It also updates information that -saveDocumentWithDelegate:didSaveSelector:contextInfo: uses to check for modification, renaming, moving, deleting, and trashing of open documents, and deletes autosaved contents files when they have become obsolete. Because this method does several diffferent things, and because the things are likely to change in future releases of Mac OS X, your override of this method should virtually always invoke super, merely adding new behavior before or after the saving.


Document Autosaving

Support for autosaving of documents has been added to Cocoa. The support takes the form of optional periodic autosaving behavior, new autosaving behavior at application-quitting time, and new NSDocument and NSDocumentController methods that you can invoke and override to customize the behavior.


New NSDocumentController Methods for Autosaving

Two new methods have been added to NSDocumentController so that you can enable periodic autosaving and control how often documents are periodically autosaved:
- (void)setAutosavingDelay:(NSTimeInterval)autosavingDelay;
- (NSTimeInterval)autosavingDelay;
The time interval in seconds for periodic autosaving. A value of 0 indicates that periodic autosaving should not be done at all. NSDocumentController will use this number as the amount of time to wait between detecting that a document has unautosaved changes and sending the document an -autosaveDocumentWithDelegate:didAutosaveSelector:contextInfo: message. The default value is 0. You can change it to enable periodic autosaving.

Two new methods that are invoked when reopening autosaved documents have been added to NSDocumentController:
- (BOOL)reopenDocumentForURL:(NSURL *)absoluteDocumentURL
withContentsOfURL:(NSURL *)absoluteDocumentContentsURL error:(NSError **)outError;
Reopen a document located by a URL by reading the contents for the document from another URL, present its user interface, and return YES if successful. If not successful, return NO after setting *outError to an NSError that encapsulates the reason why the document could not be reopened. The default implementation of this method determines the type of document being reopened, sends a -makeDocumentForURL:withContentsOfURL:ofType:error: to instantiate it, then invokes -addDocument: to record its opening. It then sends the document -makeWindowControllers and -showWindows messages.
- (id)makeDocumentForURL:(NSURL *)absoluteDocumentURL withContentsOfURL:(NSURL *)absoluteDocumentContentsURL
ofType:(NSString *)typeName error:(NSError **)outError;
Instantiate a document located by a URL, of a specified type, but by reading the contents for the document from another URL, and return it if successful. If not successful, return nil after setting *outError to an NSError that encapsulates the reason why the document could not be instantiated. The default implementation of this method invokes -documentClassForType: to find out the class of document to instantiate, allocates a document object, and initializes it by sending it an -initForURL:withContentsOfURL:ofType:error: message.


New NSDocument Methods and Enumerators for Autosaving

New methods have been added to NSDocument. New NSDocumentChangeTypes and a new NSSaveOperationType have been added too:
- (BOOL)hasUnautosavedChanges;
Return YES if the document has changes that have not been autosaved, NO otherwise, as determined by the history of previous invocations of -updateChangeCount:. The default implementation of this method returns NO immediately after invocation of -updateChangeCount:NSChangeCleared or -updateChangeCount:NSChangeAutosaved. It will then return YES if a different number of -updateChangeCount:NSChangeDone and -updateChangeCount:NSChangeUndone invocations have been done since. (-updateChangeCount:NSChangeReadOtherContents has no effect on what the default implementation of this method returns.)
- (void)autosaveDocumentWithDelegate:(id)delegate didAutosaveSelector:(SEL)didAutosaveSelector contextInfo:(void *)contextInfo;
Autosave the document's contents at an appropriate location, and then send the message selected by didAutosaveSelector to the delegate, with the contextInfo as the last argument. The method selected by didAutosaveSelector must have the same signature as:
- (void)document:(NSDocument *)document didAutosave:(BOOL)didAutosaveSuccessfully contextInfo:(void *)contextInfo;
If any error occurs while autosaving, it must be reported to the user, typically in a document-modal alert panel, before the delegate is messaged with succeeded:NO.

The default implementation of this method figures out where the autosaved document contents should go and invokes [self saveToURL:autosavedDocumentContentsURL ofType:[self autosavingFileType] forSaveOperation:NSAutosaveOperation delegate:inDelegate didSaveSelector:inDidAutosaveSelector contextInfo:inContextInfo].
- (NSString *)autosavingFileType;
Return the document type that should be used for an autosave operation. The default implementation just returns [self fileType], so for never-been-saved documents this method will return the first type in the array returned by [[self class] writableTypes], or nil if the array is empty. You can override this method and return nil in your override to completely disable autosaving of individual documents (NSDocumentController will not send -autosaveDocumentWithDelegate:didAutosaveSelector:contextInfo: to a document that has no autosaving file type.) You can also override it if your application defines a document type that is specifically designed for autosaving. For example, one that efficiently represents document contents _changes_ instead of complete document contents.
- (void)setAutosavedContentsFileURL:(NSURL *)absoluteURL;
- (NSURL *)autosavedContentsFileURL;
The location of the most recently autosaved document contents. The default implementation of -setAutosavedContentsFileURL: records the URL and notifies the shared document controller that this document should be autoreopened if the application is quit by a fast logout (a feature not in Tiger), or crashes before the document is saved. The default implementation of -autosavedContentsFileURL just returns whatever was stored by a previous invocation of the default implementation of -setAutosavedContentsFileURL:.

For example, -saveToURL:ofType:forSaveOperation:error: invokes -setAutosavedContentsFileURL: to record when autosaving has been done, and both methods as part of deleting autosaved document contents when a regular Save or Save As operation has been done successfully. -revertToContentsOfURL:ofType:error: also invokes these as part of deleting autosaved document contents.

During autosaving a new NSSaveOperationType is used:
NSAutosaveOperation
The writing of a document's current contents to a file or file package that is separate from the document's current one, without changing the document's current one. Backward binary compatibility code in NSDocument ensures that this value is never passed to overrides of methods that take NSSaveOperationTypes. NSSaveToOperation is always used in those cases instead.

After successful autosaving -updateChangeCount: with a new NSDocumentChangeType must be invoked:
NSChangeAutosaved
The value to pass to indicate that the document's contents have been autosaved. For example, -saveToURL:ofType:forSaveOperation:error: uses this for a successful NSAutosaveOperation.

A new method that you can override to customize the reopening of autosaved documents has been added:
- (id)initForURL:(NSURL *)absoluteDocumentURL withContentsOfURL:(NSURL *)absoluteDocumentContentsURL
ofType:(NSString *)typeName error:(NSError **)outError;
Initialize a document located by a URL, of a specified type, but by reading the contents for the document from another URL, and return it if successful. If not successful, return nil after setting *outError to an NSError that encapsulates the reason why the document could not be initialized. The default implementation of this method invokes [self readFromURL:absoluteDocumentContentsURL ofType:typeName error:outError], [self setFileURL:absoluteURL], [self setAutosavedContentsFileURL:absoluteDocumentContentsURL], [self setFileType:typeName], and [self setFileModificationDate:theModificationDate]. It also invokes [self updateChangeCount:NSChangeReadOtherContents] if the two URLs aren't identical, so that -isDocumentEdited will always return YES until the user saves or reverts the document.

To ease the adoption of the autosaving feature introduced in Mac OS 10.4, the default implementation of this method invokes [self initWithContentsOfFile:[absoluteDocumentContentsURL path] ofType:typeName] if -initWithContentsOfFile:ofType: is overridden and the URL uses the "file:" scheme. It still invokes [self setFileModificationDate:theModificationDate] and [self updateChangeCount:NSChangeReadOtherContents] in this situation. It still also invokes [self setFileURL:absoluteURL], to overwrite the incorrect invocation of -setFileName: that the override of -initWithContentsOfFile:ofType: likely did.

absoluteDocumentURL will be nil if the initializing is being done as part of the reopening of an autosaved document when the autosaved document had never been saved in the first place.

During autosaved document reopening -initForURL:withContentsOfURL:ofType:error: uses a new NSDocumentChangeType:
NSChangeReadOtherContents
The value to pass to -updateChangeCount: to indicate that the document has been initialized with the contents of a file or file package other than the one whose location would be returned by -fileURL, and therefore can't possibly be synchronized with its persistent representation. For example, -initForURL:withContentsOfURL:ofType:error: uses this to indicate that an autosaved document is being reopened.


NSDocument/NSDocumentController Support for Dynamically-Enabled Document Types

Several interesting Cocoa applications have implemented dynamically-enabled document types, in which support for additional document types is provided by plugins. Because NSDocumentController and NSDocument access document type declarations in Info.plist in a non-public way, developers have resorted to accessing private NSDocumentController and NSDocument instance variables directly, which is discouraged. To obviate such discouraged behavior, new methods that you can override, in addition to overriding existing methods, have been added so you can safely implement your own dynamically-enabled document typing scheme.


New NSDocumentController Methods for Dynamically-Enabled Document Types

- (NSString *)defaultType;
Return the name of the document type that should be used when creating new documents. The default implementation of this method returns the first Editor type declared in the application's Info.plist, or returns nil if no Editor type is declared. You can override it to customize the type of document that is created when, for instance, the user chooses New in the File menu.

[NSDocumentController openUntitledDocumentAndDisplay:error:] for instance always invokes this method. -[NSDocumentController validateUserInterfaceItem:] also invokes this when deciding whether or not any UI item whose action is newDocument: (the New item in the File menu, typically) should be enabled.
- (NSString *)typeForContentsOfURL:(NSURL *)inAbsoluteURL error:(NSError **)outError;
Given a URL, return the name of the document type that should be used when opening the document at that location, if successful. If not successful, return nil after setting *outError to an NSError that encapsulates the reason why the document's type could not be determined, or the fact that the document's type is just unrecognized. The default implementation of this method invokes -typeFromFileExtension:, possibly twice, passing an HFS file type string for the second invocation. The default implementation is of course subject to change however. You can override this to customize type determination for documents being opened.

[NSDocumentController openDocumentWithContentsOfURL:display:error:] and -[NSDocumentController reopenDocumentForURL:withContentsOfURL:error:] for instance always invoke this method.
- (NSArray *)documentClassNames;
Return the names of NSDocument subclasses supported by this application. The default implementation of this method returns information derived from the application's Info.plist. You can override it to return the names of document classes that are dynamically loaded from plugins.


New NSDocument Method for Dynamically-Enabled Document Types

- (NSArray *)writableTypesForSaveOperation:(NSSaveOperationType)saveOperation;
Return the names of the types to which this document can be saved for a particular kind of save operation. For every kind of save operation except NSSaveToOperation the returned array must only include types for which the the application can play the Editor role. For NSSaveToOperation the returned array may also include types for which the application can only play the Viewer role, and still more types that the application can merely export. The default implementation of this method returns [[self class] writableTypes] with, except during NSSaveToOperations, types for which +isNativeType returns NO filtered out.

You can override this method to limit the set of writable types when the documently currently contains data that is not representable in all writable types. For example, you can disallow saving to .rtf files when the document contains an attachment and can only be saved properly to .rtfd files. NSDocument currently uses this this method during save operations that present save panels, but it may be called at other times in future releases of Mac OS X.

You can invoke this method when creating a custom save panel accessory view to easily present the same set of types that NSDocument would present in its standard file format popup menu.


Proper Invocation of Existing NSDocument Methods for Dynamically-Enabled Document Types

The implementations of the existing NSDocument class methods +readableTypes, +writableTypes, and +isNativeType: have not changed significantly, but they are now invoked when you would expect them to be invoked, so that it is useful to override them. For example, each NSDocument subclass whose name is returned by -[NSDocumentController documentClassNames] is now sent a +readableTypes messages to determine the list of types than can be opened. For another example, the class of a document that is being saved is sent a +writableTypes message to determine the list of of types than can be saved. In the case of an NSSaveOperation or NSSaveAsOperation +isNativeType: is sent for each type returned by +readableTypes, to filter out export-only types.


New NSDocumentController Method to Control the Open Recents Menu

A new method has been added to NSDocumentController so that you can override it to control NSDocumentController's presentation of the standard Open Recents menu:
- (unsigned int)maximumRecentDocumentCount;
Return the maximum number of items that may be presented in the standard Open Recent menu. A value of 0 indicates that NSDocumentController will not attempt to add an Open Recent menu to your application's File menu, though NSDocumentController will not attempt to remove any Open Recent menu item if there is one already there. The default implementation returns a value that is subject to change and may or may not be derived from a setting made by the user in a System Preferences panel.


Changes in NSDocument's Handling of the 'Save' Scripting Command (Section added since WWDC)

The behavior of -[NSDocument(NSScripting) handleSaveScriptCommand:], the method that is typically invoked when a script sends a 'save' command to a document, is changed in Mac OS 10.4. It now implements the behavior described in <http://developer.apple.com/technotes/tn2002/tn2106.html>. Here's a comparison of the old and new behavior:

When an 'in' argument is provided for an already-saved document
• 10.3: Acted like 'Save As...' unless the document class returned NO for +isNativeType:typeDerivedFromFileExtension, in which case acted like 'Save a Copy...' (also known as 'Save To...'). Invoked -writeWithBackupToFile:ofType:saveOperation: directly.
• 10.4: Acts like 'Save a Copy...' Invokes -saveToURL:ofType:forSaveOperation:delegate:didSaveSelector:contextInfo:.

When an 'in' argument is provided for a never-been-saved document
• 10.3: Acted like 'Save As...' unless the document class returned NO for + isNativeType:typeDerivedFromFileExtension, in which case acted like 'Save a Copy...' Invoked -writeWithBackupToFile:ofType:saveOperation: directly.
• 10.4: Acts like 'Save As...' Invokes -saveToURL:ofType:forSaveOperation:delegate:didSaveSelector:contextInfo:.

When no 'in' argument is provided for an already-saved document
• 10.3: Acted like 'Save.' Invoked -saveDocument:.
• 10.4: Acts like 'Save.' Invokes -saveDocumentWithDelegate:didSaveSelector:contextInfo:.

When no 'in' argument is provided for a never-been-saved document
• 10.3: Acted like 'Save As...' Invoked -saveDocumentAs:.
• 10.4: Acts like 'Save,' which in this case is indistinguishable from 'Save As...,' because a save dialog must be presented to the user. Invokes -saveDocumentWithDelegate:didSaveSelector:contextInfo:.

TextEdit, which is not NSDocument-based, has been updated to implement the same behavior.


Changes in NSDocument's Handling of Editors Registered via Cocoa Bindings' NSEditorRegistration Informal Protocol (Section added since WWDC)

In Mac OS 10.3 NSDocument implemented Cocoa Bindings' NSEditorRegistration informal protocol and would tell key-value binding editors to commit and discard their changes at certain times. In Mac OS 10.4 NSDocument's handling of key-value binding editors has been refined. These methods no long tell registered editors to commit their changes:
-saveDocument:, -saveDocumentAs:, and -saveDocumentTo:, and -printDocument:.
-canCloseDocumentWithDelegate:shouldCloseSelector:contextInfo:.
-[NSDocumentController saveAll:].
Instead, these NSDocument methods now tell registered editors to commit their changes:
-saveDocumentWithDelegate:didSaveSelector:contextInfo:
-runModalSavePanelForSaveOperation:delegate:didSaveSelector:contextInfo:
-saveToURL:ofType:forSaveOperation:delegate:didSaveSelector:contextInfo: (except for NSAutosaveOperations)
-printDocumentWithSettings:showPrintPanel:delegate:didPrintSelector:contextInfo:
The end result is that any alert sheets that editors may present when asked to commit are now always presented at the right time.

-revertDocumentToSaved: now tells registered editors to discard after the user has seen the "do you want to revert?" panel and chosen "Revert," instead of before the panel is presented.

-close now tells editors to discard their changes.

-isDocumentEdited now returns YES whenever there are registered key-value binding editors.

For backward binary compatibility, NSDocument will send -commitEditingWithDelegate:didCommitSelector:contextInfo: messages to registered editors that implement the this new method, but will fall back to using the old (but not deprecated) -commitEditing message to those that don't.


Bug Fix for Instantation of NSDocumentController Subclasses (Section added since WWDC)

According to the documentation titled "Creating a Subclass of NSDocumentController:"

"The application will not ask for its shared document controller until after the applicationWillFinishLaunching: message is sent to its delegate. Therefore, you can create an instance of your sub-class of NSDocumentController in your application delegate's applicationWillFinishLaunching: method and that instance will be set as the shared document controller."

In Mac OS 10.0-10.3 this was not always true. Code within AppKit would invoke +[NSDocumentController sharedDocumentController] during the loading of your application's main nib, if it contained an Open Recent menu item, before the sending of -applicationWillFinishLaunching: to the application delegate, preventing the NSDocumentController instantiated by the application delegate from being returned by subsequent invocations of +sharedDocumentController. This was a bug and has been fixed in Mac OS 10.4. (The bug did not affect applications that have no Open Recent menu item in their main nib and let NSDocumentController add one under the first item that had a nil target and an openDocument: action, like Sketch and Property List Editor.)


Bug Fix in -[NSDocument displayName]

In Mac OS 10.3, NSDocuments began sending themselves -displayName messages for the purpose of determining whether or not the document was untitled. NSDocument's implementation of -displayName would return nil in this situation. This interfered with overrides of -displayName that invoked [super displayName] and assumed that a non-nil value would be returned (a valid assumption). This bug has been fixed. -[NSDocument displayName] no longer ever returns nil.


Removal of Obsolete Method Declarations from NSDocument.h and NSDocumentController.h

Four NSDocument methods were marked as obsolete of as Mac OS 10.0, having been superseded by methods whose behavior in the presence of multiple sheets is markedly better:

-canCloseDocument: was replaced by -canCloseDocumentWithDelegate:shouldCloseSelector:contextInfo:
-fileNameFromRunningSavePanelForSaveOperation: was replaced by -saveDocumentWithDelegate:didSaveSelector:contextInfo:
-runModalSavePanel:withAccessoryView: was replaced by -runModalSavePanelForSaveOperation:delegate:didSaveSelector:contextInfo:
-shouldCloseWindowController: was replaced by -shouldCloseWindowController:delegate:shouldCloseSelector:contextInfo:

Two NSDocumentController methods were likewise marked as obsolete at the same time:

-closeAllDocuments: was replaced by -closeAllDocumentsWithDelegate:didCloseAllSelector:contextInfo:
-reviewUnsavedDocumentsWithAlertTitle:cancellable: was replaced by -reviewUnsavedDocumentsWithAlertTitle:cancellable:delegate:didReviewAllSelector:contextInfo:

The declarations for these six methods have been removed from NSDocument.h and NSDocumentController.h. You should stop using or overriding them in your applications and start using or overriding their replacements. However, for backward binary compatibility their implementations remain in Cocoa, in categories named NSDocument(NSCompatibility) and NSDocumentController(Compatibility). If you are not able to migrate to the newer methods, you can do away with any compiler warnings caused by the changes in NSDocument.h and NSDocumentController.h by adding the following declarations to the relevant source code files in your project:
@interface NSDocument(NSDeprecatedLongAgo)
- (BOOL)canCloseDocument;
- (NSString *)fileNameFromRunningSavePanelForSaveOperation:(NSSaveOperationType)saveOperation;
- (int)runModalSavePanel:(NSSavePanel *)savePanel withAccessoryView:(NSView *)accessoryView;
- (BOOL)shouldCloseWindowController:(NSWindowController *)windowController;
@end
@interface NSDocumentController(NSDeprecatedLongAgo)
- (BOOL)closeAllDocuments;
- (BOOL)reviewUnsavedDocumentsWithAlertTitle:(NSString *)title cancellable:(BOOL)cancellable;
@end

Summary of Deprecated NSDocument Methods

Search in the above release notes for information about why each has been deprecated, and when it is still invoked.
- (NSData *)dataRepresentationOfType:(NSString *)type;
- (NSDictionary *)fileAttributesToWriteToFile:(NSString *)fullDocumentPath
ofType:(NSString *)documentTypeName saveOperation:(NSSaveOperationType)saveOperationType;
- (NSString *)fileName;
- (NSFileWrapper *)fileWrapperRepresentationOfType:(NSString *)type;
- (id)initWithContentsOfFile:(NSString *)absolutePath ofType:(NSString *)typeName;
- (id)initWithContentsOfURL:(NSURL *)absoluteURL ofType:(NSString *)typeName;
- (BOOL)loadDataRepresentation:(NSData *)data ofType:(NSString *)type;
- (BOOL)loadFileWrapperRepresentation:(NSFileWrapper *)wrapper ofType:(NSString *)type;
- (void)printShowingPrintPanel:(BOOL)flag;
- (BOOL)readFromFile:(NSString *)fileName ofType:(NSString *)type;
- (BOOL)readFromURL:(NSURL *)url ofType:(NSString *)type;
- (BOOL)revertToSavedFromFile:(NSString *)fileName ofType:(NSString *)type;
- (BOOL)revertToSavedFromURL:(NSURL *)url ofType:(NSString *)type;
- (int)runModalPageLayoutWithPrintInfo:(NSPrintInfo *)printInfo;
- (void)saveToFile:(NSString *)fileName saveOperation:(NSSaveOperationType)saveOperation
delegate:(id)delegate didSaveSelector:(SEL)didSaveSelector contextInfo:(void *)contextInfo;
- (void)setFileName:(NSString *)fileName;
- (BOOL)writeToFile:(NSString *)fileName ofType:(NSString *)type;
- (BOOL)writeToFile:(NSString *)fullDocumentPath ofType:(NSString *)documentTypeName
originalFile:(NSString *)fullOriginalDocumentPath saveOperation:(NSSaveOperationType)saveOperationType;
- (BOOL)writeToURL:(NSURL *)url ofType:(NSString *)type;
- (BOOL)writeWithBackupToFile:(NSString *)fullDocumentPath ofType:(NSString *)documentTypeName
saveOperation:(NSSaveOperationType)saveOperationType;

Summary of Deprecated NSDocumentController Methods

Search in the above release notes for information about why each has been deprecated, and when it is still invoked.
- (id)documentForFileName:(NSString *)fileName;
- (NSArray *)fileNamesFromRunningOpenPanel;
- (id)makeDocumentWithContentsOfFile:(NSString *)fileName ofType:(NSString *)type;
- (id)makeDocumentWithContentsOfURL:(NSURL *)url ofType:(NSString *)type;
- (id)makeUntitledDocumentOfType:(NSString *)type;
- (id)openDocumentWithContentsOfFile:(NSString *)fileName display:(BOOL)display;
- (id)openDocumentWithContentsOfURL:(NSURL *)url display:(BOOL)display;
- (id)openUntitledDocumentOfType:(NSString*)type display:(BOOL)display;
- (void)setShouldCreateUI:(BOOL)flag;
- (BOOL)shouldCreateUI;

NSPersistentDocument

NSPersistentDocument is a subclass of NSDocument that enables easily creating document types which are made persistent by the CoreData framework. NSPersistentDocument instances have an NSManagedObjectContext (and thus a NSPersistentStoreCoordinator - the default implementation creates a separate stack of context, coordinator and persistent store for each document, but that can be re-configured by overriding). The coordinator is created with [self model].

NSPersistentDocument by default stores data in an XML file (an XML persistent store), but that can be reconfigured to SQL or binary formats by overriding the configurePersistentStoreCoordinatorForURL:ofType:error: method.

Summary of how various document operations work:
- Open: Invokes the configure... method with the file URL, adds a store of the default type (XML). Objects will be loaded from the persistent store on demand through the document's context.
- Save: On a new document, will add a store of the default type with the user's chosen URL, then invokes save: on the context. For an already open document, just invokes save: on the context.
- Save As: For a new document, falls back to Save:. For an already open document, migrates the persistent store to the new URL and invokes save: on the context.
- Save To: Not supported in Tiger.
- Revert: Reverts or resets the context. Objects will be loaded again from the persistent store just like the Open: case.

File package support (where potentially multiple persistent stores are inside a file wrapper) is left to subclasses where managing different stores can be done by hand through the coordinator.


NSApplication Support for the Enhanced Print Apple Event

A new Enhanced Print Apple event was defined by Mac OS 10.3 (http://developer.apple.com/technotes/tn2002/tn2082.html) but Cocoa did not support it properly. In Tiger mechanisms have been added to retrofit print event support to existing applications, but they do not work in all cases. To allow you to easily create non-NSDocument-based applications that handle Print Apple events reliably, a new NSApplication delegate has been added, and one deprecated:
- (NSApplicationPrintReply)application:(NSApplication *)application printFiles:(NSArray *)fileNames
withSettings:(NSDictionary *)printSettings showPrintPanels:(BOOL)showPrintPanels;
Given that the application has been asked to print a group of files, print them. printSettings is a dictionary containing NSPrintInfo-compatible print job attributes. Your application should add them to any NSPrintInfo used to print the files, typically by invoking [[thePrintInfo dictionary] addEntriesFromDictionary:printSettings]. showPrintPanels is a flag indicating whether or not a print panel should be presented for each file being printed. If it is NO, no print panels should be presented (but print progress panels should still be presented). See -[NSPrintOperation setShowsPrintPanel:] below. Implementations of this method must return one of the following:
typedef enum NSApplicationPrintReply {
NSPrintingCancelled = 0,
NSPrintingSuccess = 1,
NSPrintingFailure = 3,
NSPrintingReplyLater = 2
} NSApplicationPrintReply;
Return NSPrintingReplyLater if the result of printing cannot be returned immediately, if printing will cause the presentation of a sheet for instance. If your method returns NSPrintingReplyLater it must always invoke -[NSApplication replyToOpenOrPrint:] when the entire print operation has been completed, successfully or not.

This delegate method replaces -application:printFiles:, which is now deprecated. If your application delegate only implements -application:printFiles: it will still be invoked, and NSApplication will use private functionality to arrange for the print settings to take effect despite the fact that an implementation of -application:printFiles: can't possibly know about them.


NSPrintInfo Support for the Enhanced Print Apple Event

Support for attributes corresponding to fields in the Enhanced Print Apple event's "with properties" parameter has been added to NSPrintInfo:
NSString *NSPrintPagesAcross; // an NSNumber containing the number of logical pages to be placed across a physical sheet
NSString *NSPrintPagesDown; // an NSNumber containing the number of logical pages to be placed down a physical sheet
NSString *NSPrintTime; // an NSDate containing the time at which printing should begin
NSString *NSPrintDetailedErrorReporting; // an NSNumber containing a boolean value
NSString *NSPrintFaxNumber; // an NSString containing a fax number
NSString *NSPrintPrinterName; // an NSString containing the name of a printer
Bug: NSPrintTime has no effect in Mac OS 10.4.


NSPrintOperation Support for the Enhanced Print Apple Event

Because presentation of the print panel during handling of the Print event is optional, but the print progress panel should always be presented, new methods have been added to NSPrintOperation to give you individual control over the two kinds of panels:
- (void)setShowsPrintPanel:(BOOL)flag;
- (BOOL)showsPrintPanel;
- (void)setShowsProgressPanel:(BOOL)flag;
- (BOOL)showsProgressPanel;
These methods replace -setShowPanels: and -showPanels, which are now deprecated. The old methods function as they did in Mac OS 10.3, but the return value of -showPanels: is ambiguous (implementation-wise, it returns the same value as -showsPrintPanel).


New NSDocument Methods for the Enhanced Print Apple Event

A new Enhanced Print Apple event was defined by Mac OS 10.3 (<http://developer.apple.com/technotes/tn2002/tn2082.html>) but Cocoa did not support it properly. In Tiger mechanisms have been added to retrofit print event support to existing applications, but they do not work in all cases. To allow you to easily create document-based applications that handle Print Apple events properly, two new methods have been added to NSDocument, and methods have been deprecated:
- (void)printDocumentWithSettings:(NSDictionary *)printSettings showPrintPanel:(BOOL)showPrintPanel
delegate:(id)delegate didPrintSelector:(SEL)didPrintSelector contextInfo:(void *)contextInfo;
Print the document. If showing of the print panel is specified, present it first, and print only if the user OKs the panel. The NSPrintInfo attributes in the passed-in printSettings dictionary should be added to a copy of the document's print info, and the resulting print info should be used for the operation. When printing is completed or has been canceled, send the message selected by didPrintSelector to the delegate, with the contextInfo as the last argument. The method selected by didPrintSelector must have the same signature as:
- (void)document:(NSDocument *)document didPrint:(BOOL)didPrintSuccessfully contextInfo:(void *)contextInfo;
The default implementation of this method first makes sure that any editor registered using Cocoa Bindings' NSEditorRegistration informal protocol has committed its changes, then invokes [self printOperationWithSettings:printSettings error:&anError]. If nil is returned it presents the error to the user in a document-modal panel before messaging the delegate. Otherwise it invokes [thePrintOperation setShowsPrintPanel:showPrintPanel] then [self runModalPrintOperation:thePrintOperation delegate:delegate didRunSelector:didPrintSelector contextInfo:contextInfo]. Your are unlikely to need to override this method.

This method replaces -printShowingPrintPanel:, which is now deprecated. For backward binary compatibility the old method is still invoked when appropriate if it is overridden. When this is done Cocoa uses private functionality to arrange for 1) the print settings to take effect despite the fact that the override of -printShowingPrintPanel: can't possibly know about them, and 2) getting notified when the print operation has been completed, so it can message the delegate at the correct time. Correct messaging of the delegate is necessary for correct handling of the Print Apple event.
- (NSPrintOperation *)printOperationWithSettings:(NSDictionary *)printSettings error:(NSError **)outError;
Create a print operation that can be run to print the document's current contents, and return it if successful. If not successful, return nil after setting *outError to an NSError that encapsulates the reason why the print operation could not be created. The NSPrintInfo attributes in the passed-in printSettings dictionary should be added to a copy of the document's print info, and the resulting print info should be used for the operation. The default implementation of this method does nothing. You must override it to enable printing in your application.

-runModalPageLayoutWithPrintInfo: is now deprecated, because it can only present an application-modal panel, which is a poor user interface in this case. Use -runModalPageLayoutWithPrintInfo:delegate:didRunSelector:contextInfo: instead. -runModalPageLayoutWithPrintInfo: is never invoked from anywhere within Cocoa, as in Mac OS 10.3 and earlier.


NSView Page Header/Footer Printing API (Section added since WWDC)

Tiger adds API that makes it easier for a Cocoa application to include page headers and footers in its printed output. This feature is off by default, but can be enabled using NSPrintInfo's new NSPrintHeaderAndFooter attribute:
APPKIT_EXTERN NSString *NSPrintHeaderAndFooter;
AppKit also recognizes an identically-named user default, so this feature can be easily tested with an existing application executable by launching the application with the default set to YES.

For example:
MyApp.app/Contents/MacOS/MyApp -NSPrintHeaderAndFooter YES

When this feature is enabled, NSView's -drawPageBorderWithSize: method, which previously did nothing, prints a header and footer on each page. (Thus any override of -drawPageBorderWithSize: will need to invoke super's implementation if it wants to inherit this behavior.) The header and footer content are provided by two new NSView methods:
- (NSAttributedString *)pageHeader;
- (NSAttributedString *)pageFooter;
NSView's implementations of these methods provide a default header that includes the print job title (which typically is the same as the document or window title) and the date, and a default footer that includes the page number and page count. A printable view class can override one or both of these methods to substitute its own content in place of these defaults.

Each of these methods is invoked once per page during printing, offering implementors the chance to provide potentially page-specific header/footer content (including an appropriate page number, and perhaps offering different content or alignment for even vs. odd pages, for example). Implementors will typically consult NSPrintOperation's printInfo object to obtain data of interest to include in the header/footer text.

Note that the use of NSAttributedString as the return type for these methods provides for a great deal of power and flexibility. Content can appear both horizontally centered and at the page corners through use of left/center/right aligned tab stops, and images can be included as text attachments.

It is left up to the client application to expose this feature in its user interface, if desired. A simple checkbox in a print sheet accessory view, or the application's Preferences panel, would suffice. An application that provided for user customization the header/footer content could opt to go further.


NSView Drawing Redirection API (Section added since WWDC)

Tiger adds three new methods to NSView that enable an application to ask a view subtree to draw into a specified NSBitmapImageRep or NSGraphicsContext. This feature can be used to take a snapshot of the drawing done by a view and its descendants, either as a cache for computationally expensive view drawing, or for use in some subsequent graphics operation. It does not currently support capture of views that render to hardware-accelerated surfaces (i.e. NSOpenGLViews and NS/QTMovieViews), but otherwise works with all Quartz-based view drawing. The views to be drawn can, but need not, reside in a window. A client can request drawing of a view's entire content, or some rectangular subregion.

Clients of this API should begin by obtaining an NSBitmapImageRep of appropriate dimensions and color depth for capturing the desired view content. Such a bitmap can be obtained using the new NSView method:
- (NSBitmapImageRep *)bitmapImageRepForCachingDisplayInRect:(NSRect)rect;
A client wishing to capture only the parts of the receiver that are not clipped by ancestor views should pass the receiver's "visibleRect" as the NSRect parameter. It is also possible to snapshot parts of a view that are currently clipped (due to an enclosing NSScrollView, for example), by specifying a rectangle that is outside the receiver's visibleRect, but still within its bounds. The -bitmapImageRepForCachingDisplayInRect: method returns a new, autoreleased NSBitmapImageRep instance that is suitable for caching a copy of the specified view area.

Once a suitable target bitmap has been obtained, the client should initialize it as desired before asking the view subtree to draw into it. To initialize the bitmap to fully transparent, for example, one could use the following code:
    NSGraphicsContext *bitmapGraphicsContext = [NSGraphicsContext graphicsContextWithBitmapImageRep:cacheBitmapImageRep];
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:bitmapGraphicsContext];
[[NSColor clearColor] set];
NSRectFill(NSMakeRect(0, 0, [cacheBitmapImageRep size].width, [cacheBitmapImageRep size].height));
[NSGraphicsContext restoreGraphicsState];
The desired view subtree area can then be drawn into the bitmap using the new method:
- (void)cacheDisplayInRect:(NSRect)rect toBitmapImageRep:(NSBitmapImageRep *)bitmapImageRep;
The "rect" parameter should be of the same size as that passed to bitmapImageRepForCachingDisplayInRect:. This method creates an NSGraphicsContext for drawing into the NSBitmapImageRep, translates its coordinate system to place the requested rectangle at the origin, and then asks the view subtree to draw into the NSGraphicsContext using another new NSView method:
- (void)displayRectIgnoringOpacity:(NSRect)aRect inContext:(NSGraphicsContext *)context;
Clients that want to set up a different transform or other graphics context parameters may also send this message directly instead of cacheDisplayInRect:toBitmapImageRep:, but will otherwise usually find the latter approach more convenient.

NSView.h contains a declaration for an additional new method:
- (BOOL)lockFocusIfCanDrawInContext:(NSGraphicsContext *)context;
This is not yet used in Tiger, but may be made functional in the future.


NSView -registeredDraggedTypes API

Tiger adds a -registeredDraggedTypes accessor to NSView. This method can be used to query a view for the set of drag types for which the view has been registered via -registerForDraggedTypes. The elements in the returned array are in no particular order, but the array is guaranteed not to contain duplicate entries.


NSView -drawPageBorderWithSize: fix (Section added since WWDC)

On previous versions of Mac OS X, locking focus to draw in an override of NSView's -drawPageBorderWithSize: method applies a transform and clip that are unsuitable for drawing in the page border area. A workaround for this issue is discussed in Cocoa : Printing : Providing a Custom Pagination Scheme. On Tiger, the workaround is no longer necessary, but will cause no harm in applications that employ it.


NSView +new Behavior Change

For applications linked on or after Tiger, NSView's +new is equivalent to [[ViewClass alloc] init], which is more consistent with the usual meaning of +new than the previous behavior of invoking [[ViewClass alloc] initWithFrame:...].

Thus, if an NSView subclass overrides -init, +new will invoke the subclass's -init implementation, whereas it would have been bypassed in favor of -initWithFrame: before.


NSView Transform Fixes

NSView's -convertRect:fromView: and -convertRect:toView: methods have been fixed in Tiger. Previously, these methods could return a rect of insufficient width or height under some transformations.


NSApplication

In Tiger, we changed the behavior of NSApplication for some modal panels. It is now possible to hide an application while a modal panel is open. It is also possible to quit an application while the open panel is up.

We now show the menuBar earlier in application launch - right after sending the applicationWillFinishLaunching notification. If your application wants to hide the menuBar on launch, you should call +[NSMenu setMenuBarVisible:NO] during applicationWillFinishLaunching.

Applications will no longer be told to open an untitled document if launched as a login item or if launched as a service provider.

The following problems were fixed:

- an application delegate that implemented only application:openFiles: (and not application:openFile:) would not be able to open recent documents.

- NSWorkspaceWillPowerOffNotification was sent whenever an application received a 'quit' AppleEvent, whether from loginwindow, the dock, or an AppleScript. This notification is now only sent for logout, restart, or shutdown.

- drawers and NSStatusItems could prevent an application whose delegate returned YES from -applicationShouldTerminateAfterLastWindowClosed: from terminating when the last window was closed.


Dragging (Section updated since WWDC)

In Tiger, we fixed a problem where the offset passed to -[NSView dragImage:at:offset:event:pasteboard:source:slideBack:] was ignored when positioning the dragged image onscreen, but not ignored when passing the drag location to the source in draggedImage:endedAt:operation:. This offset is now universally ignored, because it no longer makes sense with the underlying implementation. This fix applies only to applications built on Tiger or later for compatibility reasons.

We added a method to the NSDraggingDestination informal protocol to allow dragging destinations to specify that they are not interested in periodic -draggingUpdated messages. On Panther and previous, the dragging code sends periodic -draggingUpdated messages to a destination even if there is no change to the drag (the mouse hasn't moved and modifier flags haven't changed), as documented. We have added a new method to allow dragging destinations to override this behavior.
@interface NSObject(NSDraggingDestination)
...
- (BOOL)wantsPeriodicDraggingUpdates;
...
@end
-wantsPeriodicDraggingUpdates will be sent to the dragging destination view or window if it responds. If the destination responds and returns NO, -draggingUpdated messages will be sent only when the mouse moves or a modifier flag changes. Otherwise, the default behavior will be to continue to send periodic dragging updated messages even if nothing is changing.

We added the ability to specify an HFS promise drag without using dragPromisedFilesOfTypes:fromRect:source:slideBack:event:. A dragging source may now add the NSFilesPromisePboardType to the pasteboard directly, and should call setPropertyList:forType: to write the array of fileTypes as the data for this type. The object passed in the source argument of dragImage:at:offset:event:pasteboard:source:slideBack: must implement namesOfPromisedFilesDroppedAtDestination: to provide the file names when the drag is dropped.

We fixed a bug where hidden views could be the target of a drag.


NSEvent (Section updated since WWDC)

In Tiger, we added a constant, NSDeviceIndependentModifierFlagsMask, to be used in a bitwise-and with -[NSEvent modifierFlags] to retrieve only the device independent modifier flags. This allows applications to mask off the device dependent modifierFlags, include event coalescing information. Eg. an application could detect if any device independent modifier flags are present in theEvent using:
    if (([theEvent modifierFlags] & NSDeviceIndependentMofidierFlagsMask) != 0) ...
We fixed a long standing bug where the event passed to NSApplication and NSWindow -discardEventsMatchingMask:beforeEvent: was ignored, and all events in the queue matching the mask were discarded. For applications built on Tiger or later, we now check event times against the event passed in, and discard only those events whose event time is earlier. For applications built on Panther or earlier, we continue to discard all events in the queue matching the mask.


NSScrollWheel events (Section added since WWDC)

In order to support finer-grained scrolling required by new devices, the NSScrollWheel event and the handling of NSScrollWheel events within NSScrollView has changed. For scrollWheel mice, the delta fields may now contain fractional components. These fractional values are made available to applications built on Tiger or later. Applications built on Tiger or later which do their own handling of the NSScrollWheel event need to be prepared to deal with fractional values, for example by rounding the scroll amount computed from the event to an integral value before scrolling. Applications built on Panther or earlier will receive integral values compatible with the values received on previous releases.

In addition, new devices may send the NSScrollWheel event much more frequently, in some cases with both deltaX and deltaY of 0. These scroll events contain device dependent scroll information which allow NSScrollView to do continuous scrolling, so should be passed to super if your subclass allows NSScrollView to do the scrolling. If your subclass is doing custom scrolling, you should be prepared to ignore NSScrollWheel events whose deltaX and deltaY are both 0. This change affects applications built on Tiger and on previous releases.


Tablet event support

In Panther, tablet drivers started generating native tablet events in addition to mouse events with embedded tablet data. In Tiger, we have added API to define the tablet event types, to provide accessors for tablet event data from native tablet events and mouse events with tablet data, and to allow tablet events to be sent through the responder chain.

Tablet drivers generate tablet events in two ways. In some cases (dual-puck tablet point events, "modern" proximity events), the driver generates pure tablet events. These event have been added to NSEvent.h:
typedef enum _NSEventType {        /* various types of events */
...
NSTabletPoint = 23,
NSTabletProximity = 24,
...
} NSEventType;
Along with the corresponding masks:
enum {                    /* masks for the types of events */
...
NSTabletPointMask = 1 << NSTabletPoint,
NSTabletProximityMask = 1 << NSTabletProximity,
...
};
In other cases (single-puck tablet point events, compatibility proximity events), the driver generates mouseDown/Up/Dragged/Moved events with additional tablet data. These events can be identified by their subtype. We have published the mouse event subtypes so applications can tell when an event has tablet information. These subtypes are declared in terms of constants defined in IOLLEvent.h:
enum {        /* event subtypes for mouse events */
NSMouseEventSubtype = NX_SUBTYPE_DEFAULT,
    NSTabletPointEventSubtype = NX_SUBTYPE_TABLET_POINT,
NSTabletProximityEventSubtype = NX_SUBTYPE_TABLET_PROXIMITY
};
The NSPointerType enumeration declares the possible values returned by -pointerType. These values are declared in terms of constants that will be defined in IOLLEvent.h:
/* pointer types for NSTabletProximity events or mouse events with subtype NSTabletProximityEventSubtype*/
typedef enum {
NSUnknownPointingDevice = NX_TABLET_POINTER_UNKNOWN,
NSPenPointingDevice = NX_TABLET_POINTER_PEN,
NSCursorPointingDevice = NX_TABLET_POINTER_CURSOR,
    NSEraserPointingDevice = NX_TABLET_POINTER_ERASER
} NSPointingDeviceType;
The following enumeration declares possible values to be included in the bitwise-or returned by -buttonMask. These values are declared in terms of constants defined in IOLLEvent.h:
/* button masks for NSTabletPoint events or mouse events with subtype NSTabletPointEventSubtype */
enum {
    NSPenTipMask = NX_TABLET_BUTTON_PENTIPMASK,
    NSPenLowerSideMask = NX_TABLET_BUTTON_PENLOWERSIDEMASK,
    NSPenUpperSideMask = NX_TABLET_BUTTON_PENUPPERSIDEMASK
};
The -pressure and -subtype messages are now valid for new event types as described in the comments:
/* This message is valid for all mouse down/up/drag events */
/* This message is also valid for mouse events with subtype NSTabletPointEventSubtype and
for NSTabletPoint events on 10.4 or later */
- (float)pressure;
/* this message is valid for kit, system, and app-defined events */
/* this message is also valid for mouse down/up/drag/move events on 10.4 or later */
- (short)subtype;
In addition, we have added accessors for the fields of the tablet events:
/* this message is valid for mouse events with subtype NSTabletPointEventSubtype or
NSTabletProximityEventSubtype, and for NSTabletPoint and NSTabletProximity events */
- (unsigned int)deviceID; // system-assigned unique device ID
/* these messages are valid for mouse events with subtype NSTabletPointEventSubtype, and for NSTabletPoint events */
- (int)absoluteX; // absolute x coordinate in tablet space at full tablet resolution
- (int)absoluteY; // absolute y coordinate in tablet space at full tablet resolution
- (int)absoluteZ; // absolute z coordinate in tablet space at full tablet resolution
- (unsigned int)buttonMask; // mask indicating which buttons are pressed.
- (NSPoint)tilt; // range is -1 to 1 for both axes
- (float)rotation; // device rotation in degrees
- (float)tangentialPressure; // tangential pressure on the device; range is -1 to 1
- (id)vendorDefined;         // NSArray of 3 vendor defined shorts
/* these messages are valid for mouse events with subtype NSTabletProximityEventSubtype, and  for NSTabletProximity events */
- (unsigned int)vendorID; // vendor defined, typically USB vendor ID
- (unsigned int)tabletID; // vendor defined tablet ID
- (unsigned int)pointingDeviceID; // vendor defined ID of pointing device
- (unsigned int)systemTabletID; // system assigned unique tablet ID
- (unsigned int)vendorPointingDeviceType; // vendor defined pointing device type
- (unsigned int)pointingDeviceSerialNumber; // vendor defined serial number of pointing device
- (unsigned long long)uniqueID; // vendor defined unique ID
- (unsigned int)capabilityMask; // mask representing capabilities of device
- (NSPointingDeviceType)pointingDeviceType; // type of pointing device
- (BOOL)isEnteringProximity; // YES - entering; NO - leaving
Lastly, we have added NSResponder methods for the pure tablet event types:
@interface NSResponder : NSObject <NSCoding>
...
- (void)tabletPoint:(NSEvent *)theEvent;
- (void)tabletProximity:(NSEvent *)theEvent;
...
@end

NSWindow (Section updated since WWDC)

In Tiger, ColorSync has added the ability to update the ColorSync profile attached to a window context. On Panther and previous, the ColorSync profile was defined by the profile of the main display at window server initialization time (=login time) and was cached and used for all new window contexts. In other words, windows could not pick up an updated ColorSync profile until the user logged out and back in. Even new windows created after a ColorSync profile change were not affected by the change. In Tiger, we will maintain this behavior for windows that do not adopt the new API. The profile of the main display will continue to be cached and used for any new window context that does not indicate otherwise. Maintaining this compatibility is important for correctness in apps that are doing cached drawing, and desirable for performance reasons in less sophisticated apps.

We have exposed the new ColorSync support to windows that want to adopt it. Exposing the functionality implies updating the display profile attached to the window CGContextRef, and notifying the window when the display profile has changed.
@interface NSWindow : NSResponder
...
- (void)setDisplaysWhenScreenProfileChanges:(BOOL)flag;
- (BOOL)displaysWhenScreenProfileChanges;
...
@end
If a window returns YES for -displaysWhenScreenProfileChanges, AppKit will call CGWindowContextUpdateDisplayInfo for the window context then tell the window to display, under the following conditions:
- the majority of the window has moved to a different screen and the display profile for the current screen is different than that of the previous screen
- we receive a notification from color sync that the display profile has changed for the screen containing the majority of the window
- the window context is first created (although in this case the window would not need to be told to redisplay)

The default is NO.

We have also added a notification of when the display profile has changed, to be sent after AppKit has called CGWindowContextUpdateDisplayInfo and before the window is told to display, so that the window can update any offscreen caches:
APPKIT_EXTERN NSString *NSWindowDidChangeScreenProfileNotification;
The window delegate can automatically register for this notification by implementing a new delegate method:
@interface NSObject(NSWindowNotifications)
...
- (void)windowDidChangeScreenProfile:(NSNotification *)notification;
...
@end
Adding a child window using -addChildWindow:ordered: now causes the child window to be ordered onscreen in the correct relative location (above or below) if the receiver is onscreen.

We added support for a new window appearance where the background from the titlebar continues into the toolbar, making them appear unified. There is a new styleMask NSUnifiedTitleAndToolbarWindowMask to specify this window appearance.

The toolbar button is now optional:
- (void)setShowsToolbarButton:(BOOL)show;
- (BOOL)showsToolbarButton;

NSWindow -disableScreenUpdatesUntilFlush API (Section added since WWDC)

When a view that renders to a hardware surface (such as an OpenGL view) is placed in an NSScrollView or NSSplitView, there can be a noticeable flicker or lag when the scroll position or splitter position is moved. This happens because each move of the hardware surface takes effect immediately, before the remaining window content has had the chance to draw and flush.

To enable applications to eliminate this visual artifact, Tiger AppKit provides a new NSWindow message, -disableScreenUpdatesUntilFlush. This message asks a window to suspend screen updates until the window's updated content is subsequently flushed to the screen. This message can be sent from a view that is about to move its hardware surface, to insure that the hardware surface move and window redisplay will be visually synchronized. The window responds by immediately disabling screen updates via a call to NSDisableScreenUpdates(), and setting a flag that will cause it to call NSEnableScreenUpdates() later, when the window flushes. It is permissible to send this message to a given window more than once during a given window update cycle; the window will only suspend and re-enable updates once during that cycle.

A view class that renders to a hardware surface can send this message from an override of -renewGState (a method that is is invoked immediately before the view's surface is moved) to effectively defer compositing of the moved surface until the window has finished drawing and flushing its remaining content.
- (void)renewGState {
NSWindow *window = [self window];
if ([window respondsToSelector:@selector(disableScreenUpdatesUntilFlush)]) {
[window disableScreenUpdatesUntilFlush];
}
[super renewGState];
}
In the above example, a -respondsToSelector: check has been used to provide compatibility with previous system releases. On pre-Tiger systems, where NSWindow has no -disableScreenUpdatesUntilFlush method, the -renewGState override will have no effect.


Coalesced Updates (Section added since WWDC)

In Tiger the "coalesced updates" feature of the graphics subsystem improves drawing performance and eliminates visual tearing. However, it also causes applications which flush to the screen faster than 60 fps to stall while drawing. In order to maintain backward compatibility, there are compatibility checks in place where pre-Tiger applications which stall due to over-flushing are reverted back to Panther flushing behavior.

In order to guarantee best performance, applications should refrain from animating at rates above 60 fps. And as before, it's a good idea to use NSView's setNeedsDisplay: and related methods rather than the immediate display method whenever possible, since setNeedsDisplay: enables coalescing drawing updates from different parts of the window and reduces unnecessary flushing to the screen.

The Quartz Debug application provides debugging facilities that can help determine if an application is over-flushing.

We expect to publish a tech note or a Q&A on this topic.


NSWindow live resize optimization

In Tiger, we added content preservation for windows and views during live resize. Prior to this change, the top level view in a window marked itself as needing display in its entire bounds when the window resized. When the top level view was drawn, all subviews were drawn as well, so all views completely redrew during live resize. This isn't always necessary, since in some cases the content of the view is only changing in the newly exposed area. For example in a simple window with left to right orientation, the left side window titlebar buttons and other portions of the window titlebar do not need to redraw.

When this optimization is enabled, any view whose upper left corner moves relative to the upper left of the window is assumed to need complete redraw, because in general view content is position dependent (eg. when you move the splitView bar in the Mail viewer window, the content in the MessageTextView changes relative to the upper left corner of the window). However, any view whose upper left corner remains stationary with respect to the upper left of the window has the opportunity to preserve its content.

On Tiger, content preservation during live resize is enabled by default. However, we provide windows with a way to opt-out of this optimization. If there are no views that can take advantage of it, the window would pay an unneeded expense for preserving the old content.
@interface NSWindow : NSResponder
...
-(void)setPreservesContentDuringLiveResize:(BOOL)flag;
flag - YES to indicate that window should preserve content on live resize, NO otherwise.  Default is YES.
- (BOOL)preservesContentDuringLiveResize;
...
@end
Content preservation at the view level is disabled by default for compatibility with views that should redraw completely when resized. A view can adopt content preservation by implementing the following to return YES:
@interface NSView : NSResponder
...
- (BOOL)preservesContentDuringLiveResize;
...
@end
A view that returns YES for -preservesContentDuringLiveResize is responsible for invalidating its own dirty rects during live resize. Some views may find it convenient to implement setFrameSize: and do their own computation. Other views will want a way to get information about what has changed. We are adding a method that returns the rect representing the previously drawn content, and another method that returns rects representing the minimal area to dirty in the new bounds. These methods can be called during live resize, any time after setFrameSize: has been called on the view for the live resize operation (that is, any time after NSView's implementation of setFrameSize: has been called for that view) and before recursive display of the view hierarchy begins.
@interface NSView : NSResponder
...
/* the rect returned from -rectPreservedDuringLiveResize indicates the rect the view previously occupied,
in the coordinate system of the current bounds. This may be smaller or larger than the current bounds,
depending on whether the view grew or shrunk. The result of this method is an empty rect for a view that
returns NO from -preservesContentDuringLiveResize or a view in a window that returns NO from
-preservesContentDuringLiveResize
*/
-(NSRect)rectPreservedDuringLiveResize;
/* exposedRects - on return from this method, exposedRects contains a list of rects (at most 4)
indicating the parts of the view that are newly exposed. If the view decreased in both height and width,
this list will be empty. If the view increased in both height and width and stayed anchored in the
upper left corner (currently always true but may change in the future), this list will include a
vertical component and a horizontal component indicating the exposed "L".
count - on return, the number of rectangles in the exposedRects list. Can be 0.
The result of this method is the entire view bounds for a view that returns NO from
-preservesContentDuringLiveResize or a view in a window that returns NO from -preservesContentDuringLiveResize
*/
-(void)getRectsExposedDuringLiveResize:(NSRect[4])exposedRects count:(int *)count;
...
@end

NSWindow graphicsContext

A new API graphicsContext is added. It returns an NSGraphicsContext instance associated with the receiver for the calling thread.


New Behavior in -[NSWindow print:]

In Mac OS 10.0-10.3.x -[NSWindow print:] made a copy of [NSPrintInfo sharedPrintInfo], set some print parameters in the copy, and used the copy when creating a print operation. One of the print parameters that was set was orientation, to match the window's orientation. This was inappropriate, because it overrode whatever orientation the user had already set in the shared print info using a page setup panel. This has been fixed. -[NSWindow print:] no longer sets the printing orientation except, for backward binary compatibility, in applications linked against Mac OS 10.3 or earlier.


Window menu (Section added since WWDC)

We have added an "Arrange in Front" alternate menu item for the "Bring All to Front" menu item in the Window menu. Applications should not hard code the indices of items in the Window menu, as the addition of an alternate menu item, or any other Window menu changes, will change the indices of other menu items. We have limited this change to applications built on Tiger or later to preserve binary compatibility.


Metal window background

If you use the background color from a metal window in another window, it will not archive and unarchive correctly, and the unarchived color will lose its dynamic scaling capability. You can avoid this in a metal window by using -[NSWindow backgroundColor] or -[NSColor controlColor] to draw the metal background in custom controls.


NSWindow key view loop

Methods have been added to allow a window to automatically recalculate the key view loop after views have been added.
- (void)setAutorecalculatesKeyViewLoop:(BOOL)flag;
- (BOOL)autorecalculatesKeyViewLoop;
- (void)recalculateKeyViewLoop;
If the autorecalculatesKeyViewLoop is YES, then whenever a view is added to the window, the key view loop is dirtied and recalculated automatically when -[NSWindow selectKeyViewFollowingView] or -[NSWindow selectKeyViewPrecedingView] are called. If autorecalculatesKeyViewLoop is NO, then adding views will not dirty the key view loop and the loop will not be recalculated. You can always call explicitly recalculateKeyViewLoop to recalculate the loop and clear the dirty key view loop flag. The method is also called if the key view loop needs to be calculated when the window is first ordered in. The loop computed is the same as the default one if initialFirstResponder is not set. It is based on the geometric order of the views in the window.


Keyboard Navigation

A window's toolbar and drawers are now reachable using the keyboards <tab> navigating mechanism. The keyboard navigation system expects separate keyboard loops in the toolbar, window content, and each drawer content. For example, the keyboard loop within a window's contentView should be a complete loop (following nextKeyView/previousKeyView) which does not leave the confines of the -contentView. Keyboard navigation is able to reach other loops (for example, travel from the window content to the toolbar), via -nextValidKeyView/-previousValidKeyView. When appropriate, next/previousValidKeyView will return key views in other key loops.


NSAlert

In Tiger, we changed the instance variable names of NSAlert to be prefixed by underscores to be consistent with the AppKit naming conventions. This should not have any binary compatibility implications, but may require source changes in any NSAlert subclass that references instance variables by name. (Of course, since unless otherwise specified instance variables of Cocoa classes are private, applications should not be accessing instance variables.)


NSScreen (Section added since WWDC)

+[NSScreen screens] will no longer return multiple screens when mirroring is enabled.


Text

Text system's backing store string (as obtained by the string methods on NSTextView or NSTextStorage) now do better argument checking for applications linked on Tiger.

Turns out initWithRTF:documentAttributes:, initWithDocFormat:documentAttributes:, and initWithRTFD:documentAttributes: could cause a crash if the document failed to open and the message was sent to NSTextStorage. This has been fixed in Tiger and in 10.3.3, but in earlier 10.3.x releases the only reasonable workaround is to avoid these messages if the data being provided might fail to open. You can use the read method, or call these on NSAttributedString.


NSTypesetter

The set of API introduced as part of NSATSTypesetter in Mac OS X 10.3 Panther is moved to NSTypesetter. Applications can now implement a concrete subclass with a custom layout engine by overriding the layoutParagraphAtPoint: method.

NSSimpleHorizontalTypesetter is deprecated and its interface declaration is moved to a new header NSSimpleHorizontalTypesetter.h.

In addition to the interface migrated from NSATSTypesetter, NSTypesetter has additional new API:

paragraphCharacterRange and paragraphSeparatorCharacterRange return ranges in the character space corresponding to their glyph version counterparts. attributesForExtraLineFragment is for accessing style information that should be used for the extra line fragment. actionForControlCharacterAtIndex: is used for determining actions triggerd from a control character at index.

The new API -getLineFragmentRect:usedRect:emainingRect:forStartingGlyphAtIndex:proposedRect:lineSpacing:paragraphSpacingBefore:paragraphSpacingAfter: supercedes -lineFragmentRectForProposedRect:remainingRect: in NSATSTypesetter.


NSATSTypesetter

lineFragmentRectForProposedRect:remainingRect: is deprecated. Refer to a new API provided by the base NSTypesetter class getLineFragmentRect:usedRect:emainingRect:forStartingGlyphAtIndex:proposedRect:lineSpacing:paragraphSpacingBefore:paragraphSpacingAfter:.


NSTextView Multiple Selection (Section updated since WWDC)

The concept of selection in NSTextView has been extended in order to allow the selection of multiple discontiguous ranges at once. The two new primitives for selection are
- (void)setSelectedRanges:(NSArray *)ranges affinity:(NSSelectionAffinity)affinity stillSelecting:(BOOL)flag;
- (NSArray *)selectedRanges;
parallel to the existing setSelectedRange:affinity:stillSelecting and selectedRange methods. The existing single-range methods setSelectedRange:, setSelectedRange:affinity:stillSelecting, and selectedRange are now defined in terms of these new methods. The affinity and stillSelectingFlag arguments retain their current meanings unaltered. The ranges argument is required to be a non-nil, non-empty array of objects responding to - (NSRange)rangeValue. The selectedRanges method is guaranteed to return an array satisfying the same criteria, and in addition its elements will be sorted ascending by location, and discontiguous (i.e. if r1 appears before r2 then NSMaxRange(r1) < r2.location), and furthermore if there is more than one element then no element will have length zero.

There are several additional new NSTextView methods:
- (void)setSelectedRanges:(NSArray *)ranges;
- (NSArray *)rangesForUserTextChange;
- (NSArray *)rangesForUserCharacterAttributeChange;
- (NSArray *)rangesForUserParagraphAttributeChange;
- (BOOL)shouldChangeTextInRanges:(NSArray *)affectedRanges replacementStrings:(NSArray *)replacementStrings;
The first is a convenience method parallel to the existing setSelectedRange:. The next three are parallel to the existing rangeForUserTextChange, rangeForUserCharacterAttributeChange, and rangeForUserParagraphAttributeChange methods, obeying the same restrictions described above for selectedRanges, except that they will return nil in case the appropriate change is not permitted, in the situations in which the existing single-range methods now return (NSNotFound, 0). The last is similar to the existing shouldChangeTextInRange:replacementString:; the replacementStrings array should either be nil, or else contain one element for each range in affectedRanges.

The existing methods returning a single range will now return the first subrange where there is a multiple-range selection. This means that code that uses the existing single-range APIs will continue to operate, acting on the first selected subrange when there are multiple selections. This is in fact the appropriate behavior for many purposes, and is expected to remain a reasonable default. Most AppKit methods have been updated where appropriate to act on all of the subranges of a multiple selection, particularly methods that modify attributes.

There are two new NSTextView delegate methods:
- (NSArray *)textView:(NSTextView *)textView
willChangeSelectionFromCharacterRanges:(NSArray *)oldSelectedCharRanges
toCharacterRanges:(NSArray *)newSelectedCharRanges;
- (BOOL)textView:(NSTextView *)textView
shouldChangeTextInRanges:(NSArray *)affectedRanges
replacementStrings:(NSArray *)replacementStrings;
in which the arguments satisfy criteria like those of the return value of selectedRanges. In the first, the return value must satisfy criteria like those for the ranges argument to setSelectedRanges:affinity:stillSelecting:.

If a delegate implements the old delegate method
- (NSRange)textView:(NSTextView *)textView
willChangeSelectionFromCharacterRange:(NSRange)oldSelectedCharRange
toCharacterRange:(NSRange)newSelectedCharRange;
and not the new one, then multiple selection will effectively be disallowed; attempts to set the selected ranges will call the old delegate method with the first subrange, and afterwards only a single selected range will be set. If a delegate implements the new method, then the old one will be ignored.

If the delegate implements the old delegate method
- (BOOL)textView:(NSTextView *)textView
shouldChangeTextInRange:(NSRange)affectedCharRange
replacementString:(NSString *)replacementString;
then it will be called with an appropriate range and string. If a delegate implements the new method, then the old one will be ignored.

There are several means provided for users to make a multiple selection. First, command-selection can be used in a text view with the usual meaning--it selects new portions of the text, or unselects already selected portion. Second, option-selection can be used in a text view to make a rectangular selection; there is a distinctive cursor provided for this mode. A default is provided, NSProhibitMultipleTextSelectionByMouse, to control this behavior; if the default is set to YES, then command- and option-selection in text will not have their new special meanings, but will behave as they did in Panther. This mechanism allows the new means of selection to be turned off for applications in which they may not be desired.

In addition, two new NSFindPanelActions are provided, NSFindPanelSelectAll and NSFindPanelSelectAllInSelection, to allow selection of all instances of a particular find string; the standard find panel uses these if the control key is held down. Finally, the styles panel supports selection of all text having a particular style--this could be used, for example to select all text in a given font, then subsequently convert it to a different font, or to select all underlined text and subsequently italicize it.


Removal of Override of -attributedSubstringFromRange: in NSTextStorage Category

In Mac OS 10.0-10.3.x there was an override of -[NSAttributedString attributedSubstringFromRange:] in a private category of NSTextStorage. The override returned an instance of NSSubTextStorage, a private subclass of NSTextStorage (and therefore NSAttributedString) used by Cocoa's scripting subsystem. This NSSubTextStorage object responded to all NSAttributedString messages, but its value would change with the value of the "parent" NSAttributedString, which was not correct and caused several difficult-to-diagnose bugs. This override has been removed. NSTextStorages now return nonmutating NSAttributedStrings when sent the -attributedSubstringFromRange: message.


NSParagraphStyle

NSParagraphStyle features new methods hyphenationFactor and tighteningFactorForTruncation. Corresponding writer methods, setHyphenationFactor: and setTighteningFactorForTruncation: are added to NSMutableParagraphStyle.


NSParagraphStyle Header Level

NSParagraphStyle now defines a new attribute, the header level, an integer which should either be 0 or else in the range 1-6. This is currently used only for HTML import/export, defining whether a particular paragraph is a header or not and if so of what level. The relevant methods are
- (int)headerLevel;
on NSParagraphStyle and
- (void)setHeaderLevel:(int)level;
on NSMutableParagraphStyle.


Base writing direction

Accessor methods for the base writing direction, baseWritingDirection and setBaseWritingDirection:, have been added to NSCell, NSControl, and NSText classes.

Also, NSTextView and NSMutableAttributedString now have setBaseWritingDirection:range: API.


NSStringDrawing

New methods have been added to NSString and NSAttributedString categories defined in NSStringDrawing.h. drawWithRect:options: and boundingRectWithSize:options: offer more precise string rendering/sizing functionality.


NSFont and NSFontDescriptor

The NSFont and NSFontDescriptor classes have been restructured. NSFontDescriptor is now promoted to be the primary font reference in AppKit replacing Postscript names. Also, new functionalities such as font matching, font substitution, and font cascading are built into the NSFontDescriptor class.


NSGlyphInfo (Section added since WWDC)

The NSGlyphInfo class now conforms to the NSCopying protocol.


NSTextView Typing Attributes Delegate Method

In addition to the existing notification, NSTextView now has a new delegate method allowing the delegate to intervene to allow, prevent, or modify changes to typing attributes:
- (NSDictionary *)textView:(NSTextView *)textView
shouldChangeTypingAttributes:(NSDictionary *)oldTypingAttributes
toAttributes:(NSDictionary *)newTypingAttributes;

NSTextView undo coalescing (Section added since WWDC)

NSTextView now exposes a new method to control undo coalescing:
- (void)breakUndoCoalescing;
This is useful for instance as a way to get an app to prevent successive typing operations before and after a save from being coalesced into a single undoable item by the text view.


New Responder Methods

NSResponder now defines two new action methods that are implemented in NSTextView. The first is intended to insert a line break (as distinguished from a paragraph break). The NSTextView implementation inserts an NSLineSeparatorCharacter. The second is intended to insert a container break (typically a page break). The NSTextView implementation inserts an NSFormFeedCharacter.
- (void)insertLineBreak:(id)sender;
- (void)insertContainerBreak:(id)sender;

Text Tables (Section updated since WWDC)

The Cocoa text system now supports tables. The basic object involved is a new class, NSTextBlock, which represents a block of text that is to be laid out in a sub-region of the text container. The most important subclass is NSTextTableBlock, which represents a block of text that appears as a cell in a table. The table itself is represented by a separate class, NSTextTable, which is referenced by all of its NSTextTableBlocks and which controls their sizing and positioning.

Text blocks appear as attributes on paragraphs, as part of the paragraph style. An NSParagraphStyle now may have an array of text blocks, representing the nested blocks containing the paragraph, in order from outermost to innermost. For example, if block1 contains four paragraphs, the middle two of which are also in the inner block2, then the text blocks array for the first and fourth paragraphs will be (block1), while the text blocks array for the second and third paragraphs will be (block1, block2).

The methods implementing this are
- (NSArray *)textBlocks
on NSParagraphStyle, and
- (void)setTextBlocks:(NSArray *)array
on NSMutableParagraphStyle.

In addition, there are convenience methods on NSAttributedString for determining the range covered by a block or a table (or (NSNotFound, 0) if the given location is not in the specified block or table):
- (NSRange)rangeOfTextBlock:(NSTextBlock *)block atIndex:(unsigned)location;
- (NSRange)rangeOfTextTable:(NSTextTable *)table atIndex:(unsigned)location;
During layout, the typesetter proposes a large rect within which a particular block should fit. For the outermost block, this will be determined by the text container; for inner blocks, it will be determined by the containing block. The block object then decides what subrect of this it should actually take up. There are actually two rects that are determined: first, the layout rect, within which text in the block is to be laid out; second, the bounds rect, which also contains space for padding, borders, border decoration, margins, and so forth. The layout rect is determined immediately before the first glyph in a particular block is laid out, because it is needed for all subsequent layout of text in the block. It will often be quite tall, because at this point the height of the text laid out in the block has not yet been determined. The bounds rect is determined immediately after the last glyph in the block has been laid out, and it is based on the actual used rect for the text within the block.

The methods on NSTextBlock that are called by the typesetter are
- (NSRect)rectForLayoutAtPoint:(NSPoint)startingPoint inRect:(NSRect)rect
textContainer:(NSTextContainer *)textContainer characterRange:(NSRange)charRange;
- (NSRect)boundsRectForContentRect:(NSRect)contentRect inRect:(NSRect)rect
textContainer:(NSTextContainer *)textContainer characterRange:(NSRange)charRange;
An NSTextTableBlock will call upon its NSTextTable to perform these calculations, using its methods
- (NSRect)rectForBlock:(NSTextTableBlock *)block layoutAtPoint:(NSPoint)startingPoint inRect:(NSRect)rect
textContainer:(NSTextContainer *)textContainer characterRange:(NSRange)charRange;
- (NSRect)boundsRectForBlock:(NSTextTableBlock *)block contentRect:(NSRect)contentRect inRect:(NSRect)rect
textContainer:(NSTextContainer *)textContainer characterRange:(NSRange)charRange;
The typesetter stores the results of these methods in the layout manager. The new NSLayoutManager methods are:
- (void)setLayoutRect:(NSRect)rect forTextBlock:(NSTextBlock *)block glyphRange:(NSRange)glyphRange;
- (void)setBoundsRect:(NSRect)rect forTextBlock:(NSTextBlock *)block glyphRange:(NSRange)glyphRange;
- (NSRect)layoutRectForTextBlock:(NSTextBlock *)block glyphRange:(NSRange)glyphRange;
- (NSRect)boundsRectForTextBlock:(NSTextBlock *)block glyphRange:(NSRange)glyphRange;
- (NSRect)layoutRectForTextBlock:(NSTextBlock *)block atIndex:(unsigned)glyphIndex effectiveRange:(NSRangePointer)effectiveGlyphRange;
- (NSRect)boundsRectForTextBlock:(NSTextBlock *)block atIndex:(unsigned)glyphIndex effectiveRange:(NSRangePointer)effectiveGlyphRange;
- (NSRect)lineFragmentRectForGlyphAtIndex:(unsigned)glyphIndex effectiveRange:(NSRangePointer)effectiveGlyphRange
withoutAdditionalLayout:(BOOL)flag;
- (NSRect)lineFragmentUsedRectForGlyphAtIndex:(unsigned)glyphIndex effectiveRange:(NSRangePointer)effectiveGlyphRange
withoutAdditionalLayout:(BOOL)flag;
- (NSTextContainer *)textContainerForGlyphAtIndex:(unsigned)glyphIndex effectiveRange:(NSRangePointer)effectiveGlyphRange
withoutAdditionalLayout:(BOOL)flag;
The first two methods are used by the typesetter to store the information obtained from text blocks. The others are used during layout when it is necessary to determine what space has been taken up by previously laid blocks. The last three are variants of existing methods, that have the option of not causing additional layout; when they are called during layout, they must be called in such a way as not to force further layout so as to avoid an infinite recursion. For the same reason, the ...RectForTextBlock methods cause glyph generation but not layout; if no rect has been set, they return NSZeroRect. The layout rect should be set immediately before the first glyph in the block is laid out; the bounds rect should be set immediately after the last glyph in the block has been laid out. Under some circumstances, the bounds rect may be adjusted subsequently, as additional blocks in the same table are laid out.

At display time, the text is drawn as usual, but the text block is called upon to draw any background or border decoration while glyph backgrounds are being drawn, using the following method:
- (void)drawBackgroundWithFrame:(NSRect)frameRect inView:(NSView *)controlView
characterRange:(NSRange)charRange layoutManager:(NSLayoutManager *)layoutManager;
and again NSTextTableBlocks call upon their NSTextTable for this using its method:
- (void)drawBackgroundForBlock:(NSTextTableBlock *)block withFrame:(NSRect)frameRect
inView:(NSView *)controlView characterRange:(NSRange)charRange
layoutManager:(NSLayoutManager *)layoutManager;
The sizing and positioning model for text blocks involves a number of dimensions for each block, each of which may either have an absolute value in points or else be expressed as a percentage of the containing block. These dimensions include width, height, minimum and maximum width and height, and margin, border, and padding widths for each of the four sides. The default in each case will be 0, meaning no margin/border/padding and the natural width and height. Certain portions of the block will have their own colors, the default being nil for no color.
- (void)setValue:(float)val type:(NSTextBlockValueType)type forDimension:(NSTextBlockDimension)dimension;
- (float)valueForDimension:(NSTextBlockDimension)dimension;
- (NSTextBlockValueType)valueTypeForDimension:(NSTextBlockDimension)dimension;
- (void)setWidth:(float)val type:(NSTextBlockValueType)type forLayer:(NSTextBlockLayer)layer edge:(NSRectEdge)edge;
- (void)setWidth:(float)val type:(NSTextBlockValueType)type forLayer:(NSTextBlockLayer)layer; // Convenience method
- (float)widthForLayer:(NSTextBlockLayer)layer edge:(NSRectEdge)edge;
- (NSTextBlockValueType)widthValueTypeForLayer:(NSTextBlockLayer)layer edge:(NSRectEdge)edge;
- (void)setBackgroundColor:(NSColor *)color;
- (NSColor *)backgroundColor;
- (void)setBorderColor:(NSColor *)color forEdge:(NSRectEdge)edge;
- (void)setBorderColor:(NSColor *)color; // Convenience method sets all edges at once
- (NSColor *)borderColorForEdge:(NSRectEdge)edge;
NSTextTableBlock and NSTextTable instances have additional methods specific to table cells and to tables. For NSTextTableBlock:
- (id)initWithTable:(NSTextTable *)table startingRow:(int)row rowSpan:(int)rowSpan
startingColumn:(int)col columnSpan:(int)colSpan; /* Designated initializer */
- (NSTextTable *)table;
- (int)startingRow;
- (int)rowSpan;
- (int)startingColumn;
- (int)columnSpan;
For NSTextTable:
- (unsigned)numberOfColumns;
- (void)setNumberOfColumns:(unsigned)numCols;
- (NSTextTableLayoutAlgorithm)layoutAlgorithm;
- (void)setLayoutAlgorithm:(NSTextTableLayoutAlgorithm)algorithm;
- (BOOL)collapsesBorders;
- (void)setCollapsesBorders:(BOOL)flag;
- (BOOL)hidesEmptyCells;
- (void)setHidesEmptyCells:(BOOL)flag;

Text Lists

The Cocoa text system now supports lists. The basic object involved is a new class, NSTextList, which represents a section of text that forms a single list. The visible elements of the list, including list markers, will still appear in the text as they do for lists created by hand today. The list object, however, will allow the list to be recognized as such by the text system, so that markers and spacing can be automatically created for the user, and so that lists can be properly noted when saving in various rich text formats.

Text lists appear as attributes on paragraphs, as part of the paragraph style. An NSParagraphStyle now may have an array of text lists, representing the nested lists containing the paragraph, in order from outermost to innermost. For example, if list1 contains four paragraphs, the middle two of which are also in the inner list2, then the text lists array for the first and fourth paragraphs will be (list1), while the text lists array for the second and third paragraphs will be (list1, list2).

The methods implementing this are
- (NSArray *)textLists
on NSParagraphStyle, and
- (void)setTextLists:(NSArray *)array
on NSMutableParagraphStyle.

In addition, there are convenience methods on NSAttributedString for determining the range covered by a list and the ordinal position within a list of a particular item:
- (NSRange)rangeOfTextList:(NSTextList *)list atIndex:(unsigned)location;
- (int)itemNumberInTextList:(NSTextList *)list atIndex:(unsigned)location;
The NSTextList object itself describes the format of lists markers:
- (id)initWithMarkerFormat:(NSString *)format options:(unsigned)mask;
- (NSString *)markerFormat;
- (unsigned)listOptions;
- (NSString *)markerForItemNumber:(int)itemNum;
Here "marker" refers to the computed value for a specific ordinal position in the list, and "marker format" refers to a generic string used to specify the format for all markers in the list. The marker format is interpreted as a constant string, except for a numbering specifier, which will take the form "{<keyword>}". The currently supported values for <keyword> include decimal, lower-roman, upper-roman, lower-alpha, and upper-alpha. Thus "({decimal})" would be the format for a list number (1), (2), (3)... The only option value currently defined is NSTextListPrependEnclosingMarker, signaling that a nested list should include the marker for its enclosing super-list before its own marker.


Text Panels (Section updated since WWDC)

NSTextView now defines several action methods that are intended to bring forward panels to allow the user to manipulate paragraph spacing, links, lists, and tables in the text. TextEdit now has a menu item corresponding to each of these action methods:
- (void)orderFrontSpacingPanel:(id)sender;
- (void)orderFrontLinkPanel:(id)sender;
- (void)orderFrontListPanel:(id)sender;
- (void)orderFrontTablePanel:(id)sender;
There are now several means provided for users to add and manipulate links in text. Links can be created, manipulated, or removed using the link panel; they can also be dragged and dropped or copied and pasted to or from other applications. In addition, if a link is already present in the text, then control-clicking on the link will bring up a contextual menu with several options related to the link.

There are also several means to manipulate lists. There is a popup in the ruler that allows the selection of most basic list styles, and gives access to the list panel, which allows more general configuration of the content of list markers. The positioning of list markers and text is controlled by tab stops, which can be manipulated as usual, and the attributes of marker text may also be manipulated like those of any other text.

There are also several means to manipulate tables. The table panel can be used to add or remove rows and columns, to nest lists, and to join or split cells, as well as to manipulate border colors and sizes and background colors. Cell sizes can be manipulated directly by dragging on cell borders.


Text Import/Export (Section updated since WWDC)

The Cocoa text system can now import the following formats: plain text, RTF, RTFD, SimpleText, doc format, WordML, HTML, and WebArchive. It can now export all of these except for SimpleText. Instead of adding new methods for each new format, NSAttributedString and NSMutableAttributedString now have general-purpose methods that allow the format to be specified as a parameter. The existing methods remain as conveniences.

The new methods on NSAttributedString are:
- (id)initWithURL:(NSURL *)url options:(NSDictionary *)options documentAttributes:(NSDictionary **)dict error:(NSError **)error;
- (id)initWithData:(NSData *)data options:(NSDictionary *)options documentAttributes:(NSDictionary **)dict error:(NSError **)error;
- (NSData *)dataFromRange:(NSRange)range documentAttributes:(NSDictionary *)dict error:(NSError **)error;
- (NSFileWrapper *)fileWrapperFromRange:(NSRange)range documentAttributes:(NSDictionary *)dict error:(NSError **)error;
The first two methods are similar to the existing methods, but with the addition of an error parameter. The last two methods likewise add an error parameter, but in addition they require that the document type be specified in the document attributes dictionary. The last method returns a directory file wrapper if appropriate for the document type, otherwise a regular file wrapper.

The new methods on NSMutableAttributedString are:
- (BOOL)readFromURL:(NSURL *)url options:(NSDictionary *)opts documentAttributes:(NSDictionary **)dict error:(NSError **)error;
- (BOOL)readFromData:(NSData *)data options:(NSDictionary *)opts documentAttributes:(NSDictionary **)dict error:(NSError **)error;
which again are similar to existing methods but with the addition of an error parameter.

There are a number of new constants used in text import/export. There is a new document type
NSString *NSWebArchiveTextDocumentType;
for the WebKit WebArchive type; the actual format used is the data representation of a WebArchive.

Constants have been defined for all of the existing document attributes and options keys; the values are still specified for existing keys for backward compatibility with previous system versions. (To use them in Panther systems, use the actual string value of the identifier, where provided in the comments.) In addition, some new keys have been added (see below) and some have slightly different usages. NSCharacterEncodingDocumentAttribute is now used for both import and export of plain text documents. NSCocoaVersionDocumentAttribute still returns an NSNumber, but now it may have a floating-point value; for Tiger and later, this value will be the NSAppKitVersionNumber for the AppKit version that created the file. Previous values should be interpreted as follows: values less than 100 are pre-Mac OS X; 100 is Mac OS X 10.0 and 10.1; 102 is Mac OS X 10.2 and 10.3.

Various document attributes (author, subject, etc) can now be read and written in rich text files. Keywords for this have been defined in AppKit/NSAttributedString.h:
NSString *NSTitleDocumentAttribute;
NSString *NSCompanyDocumentAttribute;
NSString *NSSubjectDocumentAttribute;
NSString *NSAuthorDocumentAttribute;
NSString *NSKeywordsDocumentAttribute;
NSString *NSCommentDocumentAttribute;
NSString *NSEditorDocumentAttribute;
NSString *NSCreationTimeDocumentAttribute;
NSString *NSCopyrightDocumentAttribute;
TextEdit's "Document Properties" panel demonstrates the use of some of these keywords.


HTML Import/Export (Section updated since WWDC)

The Cocoa text system now imports and exports HTML. HTML import has been completely revised to use WebKit in all cases, and to make use of the new text table and list support. For Tiger, the @"UseWebKit" document option will no longer be relevant, and the NSTimeoutDocumentOption, NSWebPreferencesDocumentOption, and NSWebResourceLoadDelegateDocumentOption will always be available.

There is now an additional document option,
NSString *NSTextSizeMultiplierDocumentOption;
which specifies a scale factor for font sizes, corresponding to WebView's textSizeMultiplier, the same value that is exposed in Safari through the "Make Text Bigger/Smaller" menu and toolbar items.

The NSCharacterEncodingDocumentAttribute is now available for use in HTML export. If it is not specified, the default encoding for HTML export will be UTF-8. Characters not directly representable in the specified encoding will be represented by character references--usually numeric character references, but character entity references may be used in certain special cases. (At present some encodings may not be fully supported.)

The type of HTML generated is controlled by a new document attribute,
NSString *NSExcludedElementsDocumentAttribute;
This should be an NSArray containing strings (case-insensitive) that are names of HTML elements, plus several additional values: DOCTYPE (representing a doctype declaration) and XML (representing an XML declaration), and certain Apple-specific values described below. The elements contained in this list are those that will not be used in HTML generation; the text system will make use of any other HTML elements as it sees fit. By default, if no list is specified, the excluded elements will be those that are deprecated in HTML 4--namely APPLET, BASEFONT, CENTER, DIR, FONT, ISINDEX, MENU, S, STRIKE, and U--plus XML. When XML is on the excluded list, HTML forms will be used where there is a distinction; when it is removed from the list, XHTML forms will be used.

Clients specifying a list will have considerable control over the HTML generated, for example:

- Remove U from this list, and U will be used for underlined text (and the doctype will no longer be strict).
- Remove XML from this list, and an XML declaration will be generated, and XHTML forms will be used.
- Add STYLE to this list, and styles will be inlined rather than placed in the head.
- Remove FONT from this list, and FONT tags will be generated.
- Add B, I, SUB, and SUPER to this list, and CSS will be used for all styling.
- Conversely, add SPAN to this list, and no CSS at all will be used.
- Add A to this list, and all links will be suppressed.
- Add IMG and OBJECT to this list, and all attachments will be stripped.
- Add DOCTYPE to this list, and no doctype will be generated.
- Add META to this list, and all meta tags will be suppressed.
- Add HEAD to this list, and all head information will be suppressed (and styles will be inlined).
- Add BODY to this list, and the body tag will be omitted (but the body will still be generated).
- Add DOCTYPE, HTML, HEAD, and BODY to this list, and the result will be a bare HTML snippet (with styles inlined).
- Add DOCTYPE and every HTML tag except B and I, and the result will be a bare HTML snippet using only B and I.

The doctype generated depends on the list of elements. If XML is on the excluded list, then an HTML doctype will be used; otherwise an XHTML will be used. If any of the HTML 4 deprecated elements is not on the list, or if P is on the list, then a transitional doctype will be used; otherwise a strict doctype will be used. However, in all cases a doctype will be used only if the generated HTML actually conforms to it (for example, all of the relevant doctypes require a TITLE).

There are two Apple-specific values that may be added to the excluded elements array: Apple-converted-space and Apple-converted-tab. If these are absent from the array, then HTML export will add SPAN elements with these class names as a mechanism to preserve certain types of whitespace (tabs and multiple spaces) that otherwise have no faithful representation in HTML. If these are present in the array, then the generated HTML will not contain these somewhat unwieldy SPAN elements. There is a also a third recognized value, Apple-interchange-newline, but its use is not currently enabled. In the case of TextEdit, the presence of these values is controlled by the "Preserve white space" checkbox in the HTML portion of the open and save preferences pane.

The format of the HTML generated is also controlled by a new document attribute,
NSString *NSPrefixSpacesDocumentAttribute;
This should be an NSNumber containing an integer (default 0) representing the number of spaces per level by which certain nested HTML elements (notably elements involved in representing lists and tables) should be indented from the start of the line. This automatic indentation makes the resulting HTML more readable.


RTF

Handling of \expnd was fixed to treat the argument as quarter-points rather than half-points. (Note that in practice this bug didn't have any impact as we always follow \expnd with \expndtw, which correctly specifies the value out in twips.)

RTF files can now handle additional fractional sizes. (RTF spec allows only half-point precision.)

"No kerning" is now preserved in RTF files; it was not being written out correctly.


Command-Line Tool (Section added since WWDC)

There is now a tool, /usr/bin/textutil, that allows command-line access to the import/export facilities of the Cocoa text system. It can be used for inspecting properties of files, for altering attributes, and for conversion between any of the types of files that the text system supports. Examples might include: determining the format and metadata attributes of a file; adding or changing metadata such as author or title; converting between HTML and RTF; extracting the plain text from rich text documents; or converting plain text from one encoding to another. For more information, see "man 1 textutil".


NSFontPanel modes

We added the following modes to NSFontPanel to allow disabling font effects using validModesForFontPanel. However these are actually not yet implemented:
NSFontPanelUnderlineEffectModeMask      = 1<<8,
NSFontPanelStrikethroughEffectModeMask = 1<<9,
NSFontPanelTextColorEffectModeMask = 1<<10,
NSFontPanelDocumentColorEffectModeMask = 1<<11,
NSFontPanelShadowEffectModeMask = 1<<12,
NSFontPanelAllEffectsModeMask = 0XFFF00

Font Effects Color Changes (Section added since WWDC)

In Panther, the font effects portion of the font panel used a private mechanism to handle color changes (foreground color, underline color, strikethrough color, and document background color). In Tiger, it uses the standard changeAttributes:/convertAttributes: mechanism for foreground color, underline color, and strikethrough color, and the standard changeDocumentBackgroundColor: method for document background color. This makes it easier for custom views to respond to these color changes. The previous private mechanism will still be supported, for those views that may have implemented it based on the Panther implementation, but changeAttributes:/convertAttributes: is recommended for future use.


NSLayoutManager Screen Font Changes (Section added since WWDC)

In Panther, a layout manager would not use screen fonts if any text view associated with it was scaled or rotated, regardless of the setting of usesScreenFonts. In Tiger, a layout manager will use screen fonts if usesScreenFonts is set, regardless of the state of text views associated with it. The previous behavior remains in effect for applications linked on Panther or previous. Applications linked on Tiger or beyond will have to manually call setUsesScreenFonts: on their layout managers if they wish the use of screen fonts to change.


NSLayoutManager Glyph Generator

NSLayoutManager now has methods for directly setting and getting its glyph generator:
- (NSGlyphGenerator *)glyphGenerator;
- (void)setGlyphGenerator:(NSGlyphGenerator *)glyphGenerator;

NSSpellChecker Language Argument (Section added since WWDC)

Documentation has stated that the language argument to
- (NSRange)checkSpellingOfString:(NSString *)stringToCheck startingAt:(int)startingOffset
language:(NSString *)language wrap:(BOOL)wrapFlag inSpellDocumentWithTag:(int)tag wordCount:(int *)wordCount;
should be the empty string to specify that the user's currently selected spellchecker should be used. Actually, nil should be used instead; using the empty string would give inconsistent results on pre-Tiger system versions. For Tiger, the empty string will be handled as nil, but nil is still preferred. The same holds for the similar methods
- (int)countWordsInString:(NSString *)stringToCount language:(NSString *)language;
- (NSArray *)completionsForPartialWordRange:(NSRange)range inString:(NSString *)string
language:(NSString *)language inSpellDocumentWithTag:(int)tag;

NSFileWrapper Changes (Section added since WWDC)

- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)atomicFlag updateFilenames:(BOOL)updateFilenamesFlag;
This method was changed to be more efficient when overwriting existing directories. The change in behavior is that it tries to avoid creating new copies of any files which haven't changed.


NSToolbar (Section updated since WWDC)

NSToolbarItem menuFormRepresentation are now only validated when the toolbar is in label only mode. This is a performance win since these menuFormRepresentations are only used when the toolbar is in label only mode.

A bug was discovered in Panther that affected layout of flexibly sized "view" items when in "Icon & Text" mode. In this case, the view portion of a toolbar item was much smaller than the space which was available to it. In essence, these items looked like they had too much empty space on the right and left side. They looked much farther away from adjacent items than desired (besides the fact that the view portion was smaller than it should be). In Panther, the view portion should never have excess spacing on the right and left unless the extent of the toolbar item and its label is larger than the item's maximum specified view size.

NSToolbar now indicates the selection status of items even if they are in the overflow menu. Prior to Tiger, items in the overflow menu did not indicate selection status. Selected items are indicated using the standard menu check mark.

NSToolbarItem's with valid actions and nil targets now work much better. Normally the receiver of a nil-targeted action is found by traversing the responder chain to find a responder that implements the action method. The traversal starts with the 'firstResponder' in the keyWindow. For applications linked on Tiger or later, toolbar item's now start their traversal with the firstResponder of toolbar item's window even if it is not key.

To understand why the old behavior is a problem, imagine the following: You have a nil-targeted "save" item whose action is saveContentsOfWindow:. There are 2 windows "A" and "B" are open with A being the key window. Each window implements saveContentsOfWindow:. Prior to Tiger, validation of window B's "save" item, would always go through the A's validation code. Further, if you cmd-clicked on B's "save" item (ie. perform the click without changing the key window), the action would be executed by A.

NSToolbar validates its toolbar items once before they are shown so that it is animating with up-to-date state.

A NSToolbarItem's menuFormRepresentation that is a submenu can now have an target/action associated with the top-level item. Such items behave like pulldown menu's whose top level item is clickable like a button. If the user mouses up before the pulldown is shown, the top-level item's action is sent. The pulldown menu is shown after a short delay, or if the user moves the mouse. The action methods 'sender' argument will be the top-level menu item. This new behavior is enabled for applications linked on Tiger and later. .

The resizing behavior of NSToolbarFlexibleSpaceItemIdentifier items has changed slightly. The purpose of a flexible spacer is two-fold. First it is used by users that want to right align certain items. Second, it is use to create visual separation. Flexible spacer items used to share an equal amount of the available space with other resizable items. Unfortunately, this steals valuable space from the items with actual content. To address this, flexible spacers no longer resize with an equal weighting.

NSToolbar's layout of resizable items has been improved. For applications linked on Panther or earlier, there is a bug in the layout of resizable items in icon and label mode. Often items that should have been the same size were different in size. In particular, if two items have the same minSize, when they are both wider than their label, yet smaller then their maxSize, they should be the same size. This bug has been fixed for applications linked on or after Tiger.

Prior to Tiger, changing the label of a resizable item could sometimes cause the item to resize on the screen when it was unnecessary to resize. This bug has been fixed for applications linked on or after Tiger.

Prior to Tiger, changing the label of a resizable item could sometimes cause the item to resize on the screen when it was unnecessary to resize. This bug has been fixed for applications linked on or after Tiger.

Layout changes - NSToolbar's margins have changed slightly.

Margins in aqua windows: The inset of the first and last item have changed, but the sum of those two values is the same as in Panther. However, the inter item spacing has changed by 1 pixel per item. This results in a bit more space for the layout algorithm, resulting in slightly larger flexibly sized items.

Margins in metal windows: The layout has the same changes that the aqua windows have, plus a small vertical margin change. Metal windows are now a vertically shorter, with margins that now match Safari and Finder. As a result, metal windows with toolbars will be a few pixels shorter for the same content size.

Drawing the baseline separator: For applications that want their toolbar to look more like the Finder and Safari, NSToolbar allows you to hide the baseline it draws between itself and the main window contents. Developers can also use this API to hide the base line so that they can draw their own custom looking separator. To turn on/off baseline drawing, call the following methods before you attach your toolbar to its window:
- (void)setShowsBaselineSeparator:(BOOL)flag;
- (BOOL)showsBaselineSeparator;

NSToolbarItem

Autovalidation

NSToolbar relies on window update to drive its auto-validation mechanism to enable/disable NSToolbarItems. Unfortunately, window update may not happen at the exact moment a developer needs to update their UI. Also, window update happens very frequently, and can cause performance problems for validators that need to do a lot of work. Therefore, we now provide a way to turn off the default auto validation on a per-item basis.
/* By default NSToolbar automatically invokes its items validate method on a regular basis.
To be in complete control of when the -validate method is invoked, you can disable automatic validation
on a per-item basis. In particular, if your validation code is slow, you may want to do this for performance reasons.
*/
- (void)setAutovalidates:(BOOL)autovalidates;
- (BOOL)autovalidates;
Avoiding Overflow

Some applications would like to suggest that certain toolbar items always be visible, never falling into the overflow menu. For instance, in Safari, the URL field is very important, and should generally always be visible (and not in the overflow menu). Users may find it very useful to define this sort of thing as well. For instance, In Xcode, I might want to suggest that the "build styles" popup always be visible. To accomplish this, we added the following API.
enum {
// The default visibility priority value. By default, all items have this priority
NSToolbarItemVisibilityPriorityStandard = 0,
    // A good value to use for items which should be first to fall into the overflow menu
NSToolbarItemVisibilityPriorityLow = -1000,
    // A good value to use for items you want to stay visible, allowing users to still have highest priority
NSToolbarItemVisibilityPriorityHigh = 1000,
    // Value assigned to an item the user wants to "keep visible". You should only use values less than this
NSToolbarItemVisibilityPriorityUser = 2000
};
/* When a toolbar does not have enough space to fit all its items, it must push some into the overflow menu.
Items with the highest visibility priority level are chosen last for the overflow menu. The default
visibilityPriority value is NSToolbarItemVisibilityPriorityStandard. To suggest that an item always
remain visible, give it a value greater than NSToolbarItemVisibilityPriorityStandard, but less than
NSToolbarItemVisibilityPriorityUser. In configurable toolbars, users can control the setting of any item,
and the value is rememeber by NSToolbar along with its other autosaved information. You should allow
user setting to have the highest priority.
*/
- (void)setVisibilityPriority:(int)visibilityPriority;
- (int)visibilityPriority;
A cautionary note: The toolbar is never meant to be the only way of doing a particular function. This API should not be used as a crutch. In fact, since users can override your suggestion of what should be visible, you are still never guaranteed that an item will always be visible.


NSStatusItem

You can now get and set a separate double click action on an NSStatusItem. This action is called for any even with a clickCount of greater than 1.
- (SEL)doubleAction;
- (void)setDoubleAction:(SEL)aSelector;

NSMenu

A new method has been added to NSMenu that returns the menu bar height for the main menu. This method supersedes +[NSMenuView menuBarHeight]. The method returns the menu bar height if the menu is the application's current main menu and 0 otherwise.
- (float)menuBarHeight;

Dock Menu

In Tiger, we added support for alternate menu items in dock menus. We also added support to invoke the NSMenu delegate methods if a menu delegate is set.


NSSegmentedCell/NSSegmentedControl

A new method has been added to NSSegmentedCell and NSSegmentedControl that selects the cell given the tag. It will search for the item with the tag and then call -[NSSegmentedCell setSelectedSegment]. The function will return YES if the segment is found even if the cell isn't selectable because it's disabled. The control method calls the cell method.
- (BOOL)selectSegmentWithTag:(int)tag;

NSPopUpButtonCell/NSPopUpButton

A new method has been added to NSPopUpButtonCell and NSPopUpButton that selects an item given the tag. It will search for the item with the tag and then call -[NSPopUpButtonCell selectItemAtIndex]. The method will return YES if the item is found. If the item isn't found, the function returns NO and does nothing. The control method calls the cell method.
- (BOOL)selectItemWithTag:(int)tag;

NSFormCell

Placeholder string methods in NSTextFieldCell are also available in NSFormCell.
- (void)setPlaceholderString:(NSString *)string;
- (NSString *)placeholderString;
- (void)setPlaceholderAttributedString:(NSAttributedString *)string;
- (NSAttributedString *)placeholderAttributedString;

NSButtonCell (Section updated since WWDC)

You can now set the background colour of a borderless button. This does not affect the color of bordered buttons such as push buttons.
- (void)setBackgroundColor:(NSColor *)color;
- (NSColor *)backgroundColor;
The drawing of the button background, image, and text has been broken out into 3 separate public methods that give a subclass an override point.
- (void)drawImage:(NSImage *)image withFrame:(NSRect)frame inView:(NSView *)controlView;
- (NSRect)drawTitle:(NSAttributedString *)title withFrame:(NSRect)frame inView:(NSView *)controlView;
- (void)drawBezelWithFrame:(NSRect)frame inView:(NSView *)controlView;
These methods are called if the button has the appropriate setting. -drawBezelWithFrame:inView: is called if the button is bordered. -drawImage:withFrame:inView: and -drawTitle:withFrame:inView: will be called if the button has an image and title respectively. -drawTitle:withFrame:inView: will return the actual rectangle used to render the text (usually centered in the frame passed in.)

There are several new bezel styles available:
    NSSmallSquareBezelStyle = 10
NSTexturedRoundedBezelStyle = 11
The first is a simple square bezel that appears in the accounts preference pane in System Preferences (the '+' and '-' buttons). NSTexturedRoundedBezelStyle is used to create a button similar to the Finder's action (gear) button. It is similar in appearance to a single item segmented control.

Both have regular, pressed, and disabled appearances. The controlSize setting does not apply. NSSmallSquareBezelStyle can scale to any size and NSTexturedRoundedBezelStyle has only a single size and a fixed height.
    NSRoundRectBezelStyle = 12
This is a button with semicircular end caps. It has a gray shading from light to dark. It has regular, pressed, and disabled appearances. You should set the font to be Lucida Grande 12 point.
    NSRecessedBezelStyle = 13
This is a button with semicircular end caps. It appears to have a recessed appearance. It has regular, pressed, selected, and disabled appearances. You should set the font to be Lucida Grande 12 point. This button works when you set -setShowsBorderOnlyWhileMouseInside to YES.
    NSRoundedDisclosureBezelStyle = 14
This button is a square button that is the same as the disclosure button in the save panel. It has regular and selected states. It should not have text or an image set.


NSSearchFieldCell

A flag is available that will cause the search field cell's action to be sent without delay instead of grouping the changes together until the user pauses typing.
- (BOOL)sendsSearchStringImmediately;
- (void)setSendsSearchStringImmediately:(BOOL)flag;

NSCell

The method -setControlView: is now available in NSCell and its subclasses. The implementation in NSCell does nothing. The implementation in NSActionCell saves the view.

You can now set the cell (usually an NSTextFieldCell) to allow or disallow undo. By default, the field is set to allow undo. The undo stack is cleared when the cell begins editing.
- (void)setAllowsUndo:(BOOL)allowsUndo;
- (BOOL)allowsUndo;
You can set the line break mode of a cell for text drawing. This will allow truncation of text in the cell without needing to subclass. Calling -[NSCell setWraps:] will set the mode to NSLineBreakByWordWrapping and NSLineBreakByClipping for YES and NO respectively. -setWraps will return YES if the mode is NSLineBreakByWordWrapping or NSLineBreakByCharWrapping.
- (void)setLineBreakMode:(NSLineBreakMode)mode
- (NSLineBreakMode)lineBreakMode

NSBox (Section added since WWDC)

In Tiger, we added an optimization to draw the background of an NSBox opaquely, if the NSBox is a top level view in the window and fits other criteria. Since we have discovered some applications whose nib layout involves views which overlap the NSBox rather than being completely contained, we have enabled this optimization only for applications built on Tiger or later.


NSComboBox

Calling -[NSComboBox setUsesDataSource:] now always sets indexOfSelectedItem to -1. Prior to Tiger it didn't do this for setUsesDataSource:NO.

copyWithZone: no longer loses font information in the table. Previously, copying a combo box cell would always result in a table using the default font size, even if the combo box cell was using something different like the smallSystemFont.

NSComboBox's popup menu now only shows the scroll bar if it is necessary.

NSComboBox popup window positioning has changed a bit. If the popup can not fit below the text field, NSComboBox now places the combo box above the text field only if there is more space above the combo box than there is below. In the past, NSComboBox didn't pay attention to which side had more space. Further, if there isn't enough room on either side, NSComboBox now shrinks the window to fit on screen.

NSComboBox has fixed a bug in -indexOfSelectedItems which caused the index to be incorrect when used from the NSComboBox action in certain situations.

NSComboBoxCell can now be used inside of an NSMatrix. To function properly, the matrix should use NSTrackModeMatrix for its -mode.


NSBrowser (Section updated since WWDC)

Calling setTitle:ofColumn: during column creation now works. Prior to Tiger, calling it was not possible to set the title of the column being created using this API from either of the delegate "creation" methods: -browser:numberOfRowsInColumn: or -browser:createRowsForColumn:inMatrix:.

The titleFrame passed into drawTitleOfColumn:inRect: is now 2 pixels bigger on each side. In the past, NSBrowser used to inset value returned by titleFrameOfColumn: before calling drawTitleOfColumn:inRect:. This was the wrong thing to do, and also led to certain descenders (like "g", and "j") being clipped at the bottom. Note that the baseline of the text will not move. The new behavior applies unless you are using a subclass of NSBrowser linked before Tiger. For applications linked on or after Tiger, NSBrowserCell now defaults to using NSLineBreakByTruncatingTail for its line break mode. Set -[NSCell setLineBreakMode:] for more information on line break modes.


NSMatrix

When dirtying a cells contents, NSMatrix now pays attention to the cells -focusRingType. In the past, NSMatrix always assumed a -focusRingType of NSFocusRingTypeExterior, causing it to use [self setKeyboardFocusRingNeedsDisplayInRect:cellFrame] always, instead of just for cells that support focus rings.

NSComboBoxCell can now be used inside of an NSMatrix. To function properly, the matrix should use NSTrackModeMatrix for its -mode.


NSOutlineView

-(BOOL)isItemExpanded:(id)item; now returns NO if 'item' is not found.

NSOutlineView now returns valid results from rowForItem:, and levelForItem: when called with children of an item in progress of expanding. While a particular child item is being loaded, these methods will return valid results. Previously they returned -1 while an item was in the process of being loaded by a parent (for instance during an item expand). There is no reason this particular type of information should not be valid during load time, so it is now available.

NSOutlineView's data loading is much lazier now. Data is now requested from the data source on demand. In general, the data source will not be queried for an items data unless that item is visible, or an API is invoked which requires that data to be present.

The following methods, indicated as deprecated since before 10.0, have been removed: -(void)setAutoResizesOutlineColumn: (BOOL)resize; and - (BOOL)autoResizesOutlineColumn; If you are using these methods, switch to using: -(void)setAutoresizesOutlineColumn: (BOOL)resize; and - (BOOL)autoresizesOutlineColumn;

NSOutlineView's outline column now respects the minWidth specified in IB. In the past, NSOutlineView forced the minWidth to the a value large enough to always show the expansion cells, even if that was smaller than the minWidth you specified. This change takes effect for apps linked on or after Tiger.

Drag and Drop

For applications built on Tiger or later, NSOutlineView now allows row dragging to begin with a click in any column. Previously, dragging out was limited to the outline column. Applications built on Tiger and later, can keep the old behavior by simply overriding -(BOOL)canDragRowsWithIndexes:(NSIndexSet *)rowIndexes atPoint:(NSPoint)aPoint; to return YES only when 'aPoint' is in the outline column.

For more drag and drop changes, see NSTableView release notes.

ToolTips

For many reasons, it is difficult to add cell-level toolTips to an NSOutlineView using existing NSView API. To solve this, we are adding new API which will let your delegate supply the tooltip for a cell (column/row intersection) on demand. Note that there are no tooltip tracking tags associated with these tooltips. To take advantage of this new feature, you need to implement the delegate method:
/* When the user pauses over a cell, the value returned from this method will be displayed in a tooltip.
'point' represents the current mouse location in view coordinates. If you don't want a tooltip
at that location, return nil. On entry, 'rect' represents the proposed active
area of the tooltip. By default, rect is computed as [cell drawingRectForBounds:cellFrame].
To control the default active area, you can modify the 'rect' parameter.
*/
- (NSString *)outlineView:(NSOutlineView *)ov toolTipForCell:(NSCell *)cell rect:(NSRectPointer)rect
tableColumn:(NSTableColumn *)tc item:(id)item mouseLocation:(NSPoint)mouseLocation;

NSTableView

Misc

For applications linked on or after Tiger, NSTableView invalidates the table and header view only when the frame size or column sizes has changed. In the past, calls to -tile unnecessarily invalidated the entire table and header view.

For applications linked on or after Tiger, NSTableView's (and NSOutlineView) default data cell now defaults to using NSLineBreakByTruncatingTail for its line break mode. Set -[NSCell setLineBreakMode:] for more information on line break modes.

Deselecting the edited row now ends editing. Due to a bug, in Panther and earlier systems, deselecting sometimes ended editing and sometimes did not. This has been fixed.

Double clicking now only starts editing if the click was in the cellFrame area. Prior to Tiger, double clicking anywhere in the column/row rect started editing. In particular, this had an odd effect in NSOutlineView. So now, double clicking on the left side of the outline disclosure button no longer starts cell editing.

Menu validation has changed slightly. deselectAll: is now disabled if there is no selection in the table. selectAll: is now disabled if the table disallows multiple selections.

Changing the table background color, and grid color now cause a redisplay if needed.

NSTableView is now much more aggressive about making sure the dataCell and headerCell's controlView ivar is set. For example, in Panther and earlier systems, calling [self controlView] would normally return nil for a cell in a table. For applications linked on or after Tiger, this and other related problems have been fixed. In general, NSTableView tries to make sure calling -controlView will return a reference to itself for the cells it uses.

For applications linked on or after Tiger, removing a column from an NSTableView now results in the column's tableView reference to be set to nil.

The attributes of table column's default data cells have changed. In its -init method NSTableColumn now creates a default NSTextFieldCell data cell with the following changed attributes: setDrawsBackground=YES; font=systemFont with size systemFontSize (Lucida Grande, 13). Prior to Tiger, NSTableColumn used to set the default properties to setDrawsBackground=NO, and font=(Lucida Grande, 12). The difference used to present many problems. For instance, if you added columns to your table in code, they would have different font sizes than those from the archived nib. Further, if you chose to display the popular alternating row colors, those data cells whose setDrawsBackground was YES would obscure the blue on every other line. Finally, in most tables it is unnecessary for the cells to draw the background because the table is already drawing the background. The new attributes are only set for applications linked on Tiger and later, and only in NSTableColumn's init method. So, if you have archived nibs with the wrong font size, you should fix them by hand in IB or in code.

Also, in IB it was possible to create new columns that had different properties than the default columns you get when dragging a table from the palette.

Deprecated API

Wherever possible, NSTableView now uses NSIndexSet in its APIs. The following methods have been deprecated:
- (NSImage *)dragImageForRows:(NSArray *)dragRows event:(NSEvent *)dragEvent dragImageOffset:(NSPointPointer)dragImageOffset;
- (BOOL)tableView:(NSTableView *)tv writeRows:(NSArray *)rows toPasteboard:(NSPasteboard *)pboard;
... and replaced with NSIndexSet based versions:
- (NSImage *)dragImageForRowsWithIndexes:(NSIndexSet *)dragRows tableColumns:(NSArray *)tableColumns
event:(NSEvent *)dragEvent offset:(NSPointPointer)dragImageOffset;
- (BOOL)tableView:(NSTableView *)tv writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pboard;
Accessibility Fixes

Selecting a table row using accesibility APIs now properly consults NSTableView's shouldSelectRow: delegate API.

NSTableView now sets up more NSCell state before calling accessibilityPerformAction: when the action is NSAccessibilityPressAction. In particular, the cells controlView is set to the table, and the table's clickedRow and clickedColumn reflect the row and column of the cell receiving the NSAccessibilityPressAction. Finally, the selectedCell of the table will return the cell handling the NSAccessibilityPressAction. The idea is that NSAccessibilityPressAction should be able to be handled the same as if the user had clicked on the cell with the mouse.

Drag and Drop (Section updated since WWDC)

NSTableView has added API that lets you control where row dragging operations can begin. By default NSTableView allows drags to begin anywhere with a few exceptions: Clicks on a buttons, popup buttons, sliders and other similar controls will track the mouse instead of beginning a row drag. To customize this behavior, override the following method:
/* The return value indicates whether the table can attempt to initiate a row drag at 'mouseDownPoint'.
Return NO to disallow initiating a row drag at the given location.
*/
- (BOOL)canDragRowsWithIndexes:(NSIndexSet *)rowIndexes atPoint:(NSPoint)mouseDownPoint;
NSTable/OutlineViews that are drag destinations now revalidate drags (validateDrop: API) if the modifier keys change.

You can now customize NSTableView's (and NSOutlineView) implementation of -draggingSourceOperationMaskForLocal without subclassing. NSTableView implements the dragging source method -draggingSourceOperationMaskForLocal: for you. By default it disallows dragging to destinations outside its application while allowing any type of drag within its application. There are two options for customizing this behavior. Developers can always subclass and override this method when decisions need to be dynamic. However, In Tiger, we have added an easier way to customize the behavior. Simply use the following new method:
/* Configures the default value returned from -draggingSourceOperationMaskForLocal:.
An isLocal value of YES indicates that 'mask' applies when the destination object is in the same application.
An isLocal value of NO indicates that 'mask' applies when the destination object in an application outside
the receiver's application. NSTableView will archive the values you set.
*/
- (void)setDraggingSourceOperationMask:(unsigned int)mask forLocal:(BOOL)isLocal;
Drag and Drop - File Promise Dragging

NSTableView supports file promised drags via the new pasteboard type NSFilesPromisePboardType. To support file promise drags, clients simply add this type to the pasteboard in tableView:writeRowsWithIndexes:toPasteboard:. When a destination accepts the promise drag, it asks NSTableView to supply the files via -namesOfPromisedFilesDroppedAtDestination:. NSTableView passes the responsibility of the actual file creation to data source that specified the promise drag. It will be sent the following new data source method:
/* Returns an array of filenames for the created files (filenames only, not full paths).  The URL represents
the drop location. For more information on file promise dragging, see documentation on the
NSDraggingSource protocol and -namesOfPromisedFilesDroppedAtDestination:.
*/
- (NSArray *)tableView:(NSTableView *)tableView namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination
forDraggedRowsWithIndexes:(NSIndexSet *)indexSet;
NSOutlineView has its own version:
- (NSArray *)outlineView:(NSOutlineView *)outlineView
namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination
forDraggedItems:(NSArray *)items;
ToolTips

For many reasons, it is difficult to add cell-level toolTips to an NSOutlineView using existing NSView API. To solve this, we are adding new API which will let your delegate supply the tooltip for a cell (column/row intersection) on demand. Note that there are no tooltip tracking tags associated with these tooltips. To take advantage of this new feature, you need to implement the delegate method:
/* When the user pauses over a cell, the value returned from this method will be displayed in a tooltip.
'point' represents the current mouse location in view coordinates. If you don't want a tooltip at that location, return nil.
On entry, 'rect' represents the proposed active area of the tooltip. By default, rect is computed as
[cell drawingRectForBounds:cellFrame]. To control the default active area, you can modify the 'rect' parameter.
*/
- (NSString *)tableView:(NSTableView *)tv toolTipForCell:(NSCell *)cell rect:(NSRectPointer)rect
tableColumn:(NSTableColumn *)tc row:(int)row mouseLocation:(NSPoint)mouseLocation;

Variable Row Heights

Until now, every row in a table view was required to be the same height as every other row. This is appropriate for the vast majority of table view's uses. However, in some cases, it is limiting. Sometimes it can be beneficial to specify the height of a row based on the data that row needs to display. In Tiger, we will allow table view rows to be specified per row if necessary with the following API:
/* If the delegate implements -tableView:heightOfRow:, this method immediately re-tiles the table view using row heights it provides.
*/
- (void)noteHeightOfRowsWithIndexesChanged:(NSIndexSet *)indexSet;

@interface NSObject (NSTableViewDelegate)
/* Optional - Variable Row Heights
Implement this method to support a table with varying row heights. The height returned by this method should not include
intercell spacing and must be >0. Performance Considerations: For large tables in particular, you should make sure that this
method is efficient. NSTableView may cache the values this method returns. So if you would like to change a row's height make
sure to invalidate the row height by calling -noteHeightOfRowsWithIndexesChanged:. NSTableView automatically invalidates its
entire row height cache in -reloadData, and -noteNumberOfRowsChanged.
*/
- (float)tableView:(NSTableView *)tableView heightOfRow:(int)row;
@end
@interface NSObject (NSOutlineViewDelegate)
/* Optional - Variable Row Heights
Implement this method to support an outline view with varying row heights. The height returned by this method should not include
intercell spacing and must be >0. Performance Considerations: For large tables in particular, you should make sure that this
method is efficient. NSTableView may cache the values this method returns. So if you would like to change a row's height make
sure to invalidate the row height by calling -noteHeightOfRowsWithIndexesChanged:. NSTableView automatically invalidates its
entire row height cache in -reloadData, and -noteNumberOfRowsChanged.
*/
- (float)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(id)item;
@end
Some notes about variable row height table view's:
- The lineScroll of the table's scroll view is controlled by -rowHeight.
- The height of "filler" rows is controlled by -rowHeight. Ie. The distance between grid lines, and alternating row colors past the last table row.


Table Column Resizing - Better algorithm / New APIs

NSTableView currently supports two column autoresizing modes: "resize all" and "resize last".

We are changing behavior of the current "resize all" mode. Its behavior is simplistic and not useful. Currently, as the table resizes, it sets the width of each resizable column to (availableWidth / numResizableColumns), contraining to each min and max. This distribution algorithm doesn't take into account the current relative sizes of each column. This behavior will be replaced with an algorithm that uniformly distributes space while taking into account initial values. The current "resize last" resizes the last resizable column until it reaches its min or max width. This behavior will be retained.

In addition to the existing modes, we will be adding a few more column autoresizing modes to NSTableView. In particular, we are adding a mode which allow developers to turn off column autoresizing. This will be useful for those that want to implement their own column autoresizing algorithm.

Note: "autoresizing" refers to column resizing in response to a frame change. Think live resize. "User resizing" refers to resizing by dragging from the right edge of a column header.

Also note, NSTableView's -sizeToFit, and -sizeLastColumnToFit behavior has been fixed as part of this work to use the new styles and algorithms. During a live resizing operation, these methods use the specific resizing style you have choosen via -setColumnAutoresizingStyle:. When called outside a live resize operation, -sizeToFit resizes columns to fit the visible width using NSTableViewUniformColumnAutoresizingStyle, while -sizeLastColumnToFit resizes columns using NSTableViewLastColumnOnlyAutoresizingStyle.
/* The column auto resizing style controls resizing in response to a table view frame change.
Compatability Note: This method replaces -setAutoresizesAllColumnsToFit:.
*/
typedef enum {
// Turn of column autoresizing
NSTableViewNoColumnAutoresizing = 0,
    // Autoresize all columns by distributing equal shares of space simultaeously
NSTableViewUniformColumnAutoresizingStyle,
    // Autoresize each table column one at a time.
// Proceed to the next column when the current column can no longer be autoresized (when it reaches maximum/minimum size).
NSTableViewSequentialColumnAutoresizingStyle, // Start with the last autoresizable column, proceed to the first.
NSTableViewReverseSequentialColumnAutoresizingStyle, // Start with the first autoresizable column, proceed to the last.
    // Autoresize only one table column one at a time.
// When that table column can no longer be resized, stop autoresizing.
// Normally you should use one of the Sequential autoresizing modes instead.
NSTableViewLastColumnOnlyAutoresizingStyle,
NSTableViewFirstColumnOnlyAutoresizingStyle
} NSTableViewColumnAutoresizingStyle;
- (void)setColumnAutoresizingStyle:(NSTableViewColumnAutoresizingStyle)style;
- (NSTableViewColumnAutoresizingStyle)columnAutoresizingStyle;

/* Deprecated in Mac OS 10.4.  You should use setColumnAutoresizingStyle: instead.
To preserve compatibility, if flag is YES, This method calls setColumnAutoresizingStyle:NSTableViewUniformColumnAutoresizingStyle.
If flag is NO, this method calls setColumnAutoresizingStyle:NSTableViewLastColumnOnlyAutoresizingStyle.
*/
- (void)setAutoresizesAllColumnsToFit:(BOOL)flag;
- (BOOL)autoresizesAllColumnsToFit;

NSTableColumn's resizing characteristics now provide finer controls. We have added API which allows you to declare that the user can resize a column, but that it should not resize during live resize (autoresizing).
/* The resizing mask controls the resizability of a table column.  Compatability Note: This method replaces setResizable.
*/
- (void)setResizingMask:(unsigned)resizingMask;
- (unsigned)resizingMask;
enum {
NSTableColumnNoResizing = 0, // Disallow any kind of resizing.
NSTableColumnAutoresizingMask = ( 1 << 0 ), // This column can be resized as the table is resized.
NSTableColumnUserResizingMask = ( 1 << 1 ), // The user can resize this column manually.
};
/* Deprecated in Mac OS 10.4.  If flag is YES, calls
setResizingMask:(NSTableColumnUserResizingMask | NSTableColumnAutoresizingMask).
If flag is NO, calls setResizingMask:(NSTableColumnNoResizing).
*/
- (void)setResizable:(BOOL)flag;
- (BOOL)isResizable;


Bindings and Binding Options (Section updated since WWDC)

The names of all the bindings and options used in AppKit are now declared through explicit constants in NSKeyValueBinding.h.

To debug problems with key-value coding and key-value observing related to bindings, you can now set a user default NSBindingDebugLogLevel to get more useful logs about the problems (instead of undefined key exceptions, for example). This may be useful when you try to find a misconfigured binding in a large nib file with many bindings. Set the default value to 1 to turn on logging, and to 0 to turn it off.

A new method for returning information about the current bindings of an object has been added to NSObject:
- (NSDictionary *)infoForBinding:(NSString *)binding;
It returns a dictionary with information about an existing binding or nil if it is not bound. See NSKeyValueBinding.h for more details.

Several new bindings are available:
- NSTextView now has an attributedString binding (available if multiple fonts are allowed or not).
- NSView and subclasses now have a toolTip binding.
- NSWindow now has displayPatternTitle bindings to specify the window title through a pattern string with multiple values (and work the same way as the displayPatternValue bindings on text fields).
- NSBox now has a title and displayPatternTitle bindings (that work like the bindings on NSWindow).
- NSSearchField now has a predicate binding (and if bound exposes additional predicate2, predicate3, etc. bindings) - you specify a display name and a prediate format string through the binding's options and typically bind them to the filterPreciate of an array controller.
- NSTableView now has doubleClickArgument/doubleClickTarget bindings that work the same way as the argument/target bindings of buttons - the bindings are used to trigger a method invocation on a double-click in the table view.
- Selection widgets (NSPopUpButton/NSPopUpButtonCell and NSMatrix) now offer a contentObjects binding in addition to the content and contentValues bindings (the contentObjects binding becomes available only if content is bound). This allows you to bind the content of the widget to an array (content binding), the displayed values to a dependent array (contentValues binding - which needs to use a key path that is an extension to the one of the content binding), and the "represented" objects to be handled through the selectedObject/selectedObjects bindings to another depdendent array (contentObjects - which also needs to use a key path that is an extension to the one of the content binding). For example, if you have an array with dictionaries (that can be bound to a controller through the "selection.dictionaries" key) which each have values for a key "displayName" and a key "representedObject", you can bind content of a pop-up button to "selection.dictionaries", contentValues to "selection.dictionaries.displayName" and contentObjects to "selection.dictionaries.representedObject" - the selectedObject will then operate on the "representedObject" values, while the pop-up displays the "displayName" values in the user interface. Of course, if you do not use the contentObjects binding, the represented objects are still the values in the array to which content is bound.

An option for the value bindings on table columns has been added:
NSCreatesSortDescriptorBindingOption
This option can be used to suppress the creation of sort descriptors on a column (binding) basis.

An option to force bindings to handle errors with alert panels instead of sheets has been added to varioius bindings:
NSAlwaysPresentsApplicationModalAlertsBindingOption
A variety of bugs have been fixed, some of the fixes caused a slight change in the behavior of bindings/controllers:
- For bindings with immediate validation turned on, the user interface now correctly reflects values immediately when coerced in the validateValue:forKey: method.
- Bindings on table columns with pop-up data cells and content, contentValues and selectedObject bindings now generate sort descriptors for the selected objects based on the display key (as determined from the contentValues binding).
- Unless explicitly specified, table view content, selectionIndexes and sortDescriptor bindings are automatically generated, derived from the common cases of bindings of table columns. These automatic table view bindings are now created by invoking the public -bind:toObject:withKeyPath:options: on the table view, so that subclasses can intercept the calls if needed.
- In the Panther implementation, when removing objects in the background from the array to which an NSArrayController content was bound (not removing through the controller), an index-out-of-bounds exception was sometimes raised. This situation has been fixed for Tiger.
- In Panther, copying the arrangedObjects array of an NSArrayController copied the items in the array as well. This situation has been fixed for Tiger, now the content objects are not copied any more.
- In Panther, collection values (NSArrays and NSDictionaries) read from an NSUserDefaultsController were returned as immutable collections, making it impossible to add or remove from them directly. The workaround was to use a value transformer to make mutable copies of the collections on read. For Tiger, NSUserDefaultsController now returns collections as mutable instances, which makes the use of a special value transformer obsolete (but you still usually need to turn on the NSHandlesContentAsCompoundValueBindingOption option if you bind the content of an NSArrayController or NSObjectController to a value provided through an NSUserDefaultsController).
- Interface Builder now correctly calls -exposedBindings to populate the Bindings inspector.


NSEditor, bindings error presentation as sheets (Section added since WWDC)

So that support for bindings in Cocoa's own views can present error alerts as sheets when appropriate, a new method has been added to key-value binding's NSObject (NSEditor) category:
- (void)commitEditingWithDelegate:(id)delegate didCommitSelector:(SEL)didCommitSelector contextInfo:(void *)contextInfo;
Given that the receiver has been registered with -objectDidBeginEditing: as the editor of some object, and not yet deregistered by a subsequent invocation of -objectDidEndEditing:, attempt to commit the result of the editing. When committing has either succeeded or failed, send the selected message to the specified object with the context info as the last parameter. The method selected by didCommitSelector must have the same signature as:
- (void)editor:(id)editor didCommit:(BOOL)didCommit contextInfo:(void *)contextInfo;
If an error occurs while attempting to commit, because key-value coding validation fails for example, an implementation of this method should typically send the NSView in which editing is being done a -presentError:modalForWindow:delegate:didRecoverSelector:contextInfo: message, specifying the view's containing window.

Various Cocoa classes use this method whenever possible, instead of the existing -commitEditing method, to enable proper use of sheets when presenting errors. The existing -commitEditing method is not deprecated however, because there are situations in which the success or failure of commitment must be known immediately. Implementations of -commitEditing should typically use -presentError: if an error occurs.

The bindings and controller default implementation of the NSEditor methods will use the new NSResponder-based error presentation API, so that error handling can be customized by individual applications.

Also, due to the sheet based error handling, controller action methods like add:, remove:, fetch:, etc. will now execute their operations deferred, so when the methods return, the operation is not actually performed (it will be later, but programmatic invocations of the action methods cannot rely on the operation to have completed).

CoreData's NSManagedObjectContext does implement both the NSEditor and the NSEditorRegistration methods, like NSController does.


NSObjectController

NSObjectController (and thus the subclasses NSArrayController and NSTreeController) has the following new API to specify a managed object context and a description for how to fetch objects from it (by entity name and fetch predicate). The entity name (if specified) also determines how new objects are created (instead of using a class name).
- (NSManagedObjectContext *)managedObjectContext;
- (void)setManagedObjectContext:(NSManagedObjectContext *)managedObjectContext;
- (NSString *)entityName;
- (void)setEntityName:(NSString *)entityName;
- (NSPredicate *)fetchPredicate;
- (void)setFetchPredicate:(NSPredicate *)predicate;
- (void)fetch:(id)sender;

NSTreeController

Tiger introduces a new controller class in Cocoa, NSTreeController, for managing hierarchical data structures. Much of the API of this class parallels that of the array controller. This class, in conjunction with the new NSIndexPath class in Foundation, enables displaying a tree of model objects in a NSOutlineView or NSBrowser.

Much of the API in this class is either inherited from NSController and NSObjectController or is designed to be similar to the API of the NSArrayController. Many of the concepts are the same except that objects are addressed by NSIndexPath instead of int.

Content of the tree controller can be set to the root of the tree of model objects. Clients can then progressively traverse parts of the tree as necessary by getting model objects based on an NSIndexPath, which represents their depth-first location in the tree. This removes the need for us to pull the entire tree into memory up front. On the down side, this prevents us from offering selectObject: functionality since we don't want to pay the penalty of doing a depth first search for an object in an unordered tree.

The NSTreeController traverses its content tree by using key value coding to find the children of a model object. There are methods for setting the key to use to traverse the tree, as well as 2 other keys used as performance improvement opportunities. If a model object in the tree can report the number of children it has, we can use the countKey to find the number of children instead of getting the entire child array just to message it count. Likewise, we can stop traversing a sub-tree once we encounter an object that tells us it is a leaf node in the tree by return YES for the key set as the leafKey.

It should be noted that because of the nature of selections in unordered trees, implementation of the preservesSelection feature maybe pretty expensive for large, sparse selections combined with broad trees.


NSArrayController (Section added since WWDC)

NSArrayController now supports filtering with NSPredicates:
- (void)setFilterPredicate:(NSPredicate *)filterPredicate;
- (NSPredicate *)filterPredicate;
- (void)setClearsFilterPredicateOnInsertion:(BOOL)flag;
- (BOOL)clearsFilterPredicateOnInsertion;
The filter predicate can be bound to the (enumerated) predicate bindings of NSSearchFields (use the NSDisplayNameBindingOption and NSPredicateFormatBindingOption options to configure the bindings) to automatically set up filtering in the user interface.

NSArrayController also has a new mode to handle multiple selections:
- (void)setAlwaysUsesMultipleValuesMarker:(BOOL)flag;
- (BOOL)alwaysUsesMultipleValuesMarker;
By default, the array controller will look at values of selected objects on a key-by-key basis and indicate selections of multiple different values through the NSMultipleValuesMarker, but provide the common value if all selected objects have the same value. If alwaysUsesMultipleValuesMarker is set to YES, it will use the NSMultipleValuesMarker for all selections with two or more objects (you will typically also set NSAllowsEditingMultipleValuesSelectionBindingOption option of the various value bindings for controls bound to the array controller's selection to NO). This new flag is very useful in applications with very large arrays of objects that don't want to allow editing multiple selected objects at all and also results in strong performance enhancements in certain situations with large arrays.


NSUserDefaultsController (Section added since WWDC)

NSUserDefaultsController has a new method to indicate whether there are unapplied changes:
- (BOOL)hasUnappliedChanges;
For example, you can bind the enabled state of buttons to this method.


NSGraphicsContext

The NSGraphicsContext class now has API to specify the compositing operation setting: compositingOperation and setCompositingOperation:. As with other graphics context state, the setting is saved/restore via saveGraphicsState and restoreGraphicsState methods. The setting has no effect with existing rendering API that take compositing operation as an argument such as -[NSImage compositeToPoint:operation:].

The NSGraphicsContextDestinationAttributeName now allows an instance of NSBitmapImageRep as its value. Currently only non-planar NSBitmapImageRep instances are supported. A convenience factory method graphicsContextWithBitmapImageRep: is also added.

As an example of usage, the following code will resample the bitmap in srcRep to be width x height, with the result going to outputRep:
    NSBitmapImageRep *outputRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
pixelsWide:width pixelsHigh:height bitsPerSample:8 samplesPerPixel:4
hasAlpha:YES isPlanar:NO colorSpaceName:NSCalibratedRGBColorSpace
bytesPerRow:0 bitsPerPixel:0];
    NSGraphicsContext *ctxt = [NSGraphicsContext graphicsContextWithBitmapImageRep:bitmapImageRep];
    [NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:ctxt];
[[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];
[srcRep drawInRect:NSMakeRect(0, 0, width, height)];
[NSGraphicsContext restoreGraphicsState];

A factory method graphicsContextWithGraphicsPort:flipped: is added. You can instantiate NSGraphicsContext from any arbitrary CGContextRef using this method. The initialFlippedState argument determines the initial flippedness setting returned from the -isFlipped method.

The class now has the flipped setting accessible via the isFlipped method. The recommended way to determine the current flipped state of rendering coordinate system is now [[NSGraphicsContext currentContext] isFlipped] instead of [[NSView focusView] isFlipped]. Note, as with NSView's counterpart, this setting does not necessarily reflect the current coordinate system.


NSAffineTransform (Section added since WWDC)

The NSAffineTransform class implementation moved from AppKit to Foundation. -transformBezierPath:, -set, and -concat methods are now part of a category implemented in AppKit.


NSBitmapImageRep (Section updated since WWDC)

You can now get and set custom gamma values for PNG files using the NSImageGamma property. If set in the file, the property is set in the bitmap image rep on reading and is used when saving the bitmap as PNG data.

NSBitmapImageRep now supports alternate arrangements of alpha values and formats. The following enum and methods have been added:
typedef enum {
NSAlphaFirstBitmapFormat = 1 << 0, // 0 means is alpha last (RGBA, CMYKA, etc.)
NSAlphaNonpremultipliedBitmapFormat = 1 << 1, // 0 means is premultiplied
NSFloatingPointSamplesBitmapFormat = 1 << 2     // 0 means integer
} NSBitmapFormat;
- (id)initWithBitmapDataPlanes:(unsigned char **)planes
pixelsWide:(int)width pixelsHigh:(int)height bitsPerSample:(int)bps
samplesPerPixel:(int)spp hasAlpha:(BOOL)alpha isPlanar:(BOOL)isPlanar
colorSpaceName:(NSString *)colorSpaceName
bitmapFormat:(NSBitmapFormat)bitmapFormat bytesPerRow:(int)rBytes bitsPerPixel:(int)pBits;
- (NSBitmapFormat)bitmapFormat;
Returns new bitmap image rep using the specified format. Invalid formats will cause the method to return nil. For example, setting a floating point format requires bits/sample to be 32 (though we may support double or so-called half floating point values in the future.). The bitmap format may also be set to non-zero when loading in images from files. For example, PNG files are now loaded in with a format of NSAlphaNonpremultipliedBitmapFormat.

Return format image is in either from loading file or via -initWithBitmapDataPlanes:... or -initWithFocusedViewRect... If created using the older APIs that don't take a bitmap format, the format defaults to 0 (alpha last, premultiplied, integer)

By default, the new formats will be returned for cases where the source of the bitmap data is in the new format (floating point, non-premutliplied, etc.). Pre-Tiger compiled apps will still get the old premultiplied RGBA format. You can also enable or disable it explicity by setting the NSOldBitmapFormatOnly default to YES or NO. -initWithFocusedViewRect: will continue to return bitmap format 0 images.

You can now specify NSJPEG2000FileType as the output format to write JPEG 2000 files.

You can now specify progressive JPEG saving via the bitmap property NSImageProgressive to output progressive JPEG images.

When reading or writing a JPEG file, you can include an NSDictionary as the NSImageEXIFData bitmap image property.

Methods are now available that set/get the color info for a pixel in an NSBitmapImageRep. If the image rep is part of an NSImage and the rep is cached by the NSImage then changing the pixel values may not show up when drawing the image. If you do place the rep inside an image and intend to modify it, use [image setCacheMode:NSImageCacheNever]. For -getPixel:atX:y: and -setPixel:atX:y: you must supply an array to match the rep's samples per pixel and the range of values are based on the rep's bits per sample (e.g. if bps is 4, then values returned are from 0 to 15). Setting values out of range are not defined. If the bitmap has floating point samples, the actual values returned are floats. Similarly, pixel order and premultiplication are assumed to match the rep's bitmap format.
- (void)setColor:(NSColor *)color atX:(int)x y:(int)y;
- (NSColor *)colorAtX:(int)x y:(int)y;
- (void)getPixel:(unsigned int[]) atX:(int)x y:(int)y;
- (void)setPixel:(unsigned int[]) atX:(int)x y:(int)y;
If you do not pass in explicit planes and bytesPerRow values when creating an NSBitmapImageRep, the buffer pointer returned may no longer be the first byte of a malloc'ed block and the bytesPerRow may be padded with extra bytes for performance. If you traverse the bytes, do not assume that bytesPerRow = width * bitsPerSample / 8 otherwise the image may appear skewed.

If you modify the bits of an NSBitmapImageRep directly, you may find cases where the image does not draw the updated image because we now allow Quartz to cache the pixels (possibly in video memory). If you request the bitmap data pointer via -[NSBitmapImageRep getBitmapDataPlanes:] or -[NSBitmapImageRep bitmapData] then the cached information will be cleared and subsequent draws will draw the updated image. If your application just requests the bitmap data pointer once and then continuously modifys it, the image may not update.


NSImage and NSCachedImageRep caching behavior

The behavior of NSCachedImageRep has changed to improve performance when Quartz Extreme is enabled. These changes may affect your code. If the image rep is created via -[NSCachedImageRep initWithSize:depth:separate:alpha:] then after drawing, the image will be be copied from the offscreen window where it is stored and the window may be released. Do not rely on the window or the rectangle to be valid outside of NSImage -lockFocus/unlockFocus calls. If you need the window, calling -[NSCachedImageRep window] will return a valid new window and rectangle that can be used until the next time -[NSCachedImageRep draw] call is made. If the NSCachedImageRep is created via -[NSCachedImageRep: initWithWindow:rect:], after drawing, the contents of the window will be copied and may not reflect the current window contents when drawn later. If you want the imageRep to reflect the current window contents, calling -[NSCachedImageRep window] will release any cached information.


NSImageView now supports cut:, copy:, paste:, and delete: (Section added since WWDC)

For Tiger, NSImageView has acquired action methods that enable it to automatically support cut, copy, and paste behavior. This can pose a compatibility problem for some applications, however, as an NSImageView that is not the firstResponder, but is in the responder chain by virtue of being an ancestor of the firstResponder view, may consume -cut:, -copy:, -paste:, and -delete: action messages that would previously have been passed up the responder chain to a different intended recipient.

By default, NSImageView will provide the new behavior for applications built on Tiger, while suppressing it for compatibility for applications built on Panther and earlier. To allow applications to override this decision and disable or enable the new functionality on a per-instance basis, we have added a new "allowsCutCopyPaste" attribute, and the following corresponding accessor API, to NSImageView:
@interface NSImageView
- (BOOL)allowsCutCopyPaste;
- (void)setAllowsCutCopyPaste:(BOOL)flag;
@end

NSImageCell Animation Playback

Occasionally, the frames in an animaged GIF image will specify a playback duration of zero. On Panther, an animation-enabled NSImageCell plays such an animation back with no delay between frames (i.e. as fast as possible). On Tiger, NSImageCell clamps the frame duration to a minimum of 1/30 of a second, matching the way that Safari and Internet Explorer handle such GIFs.


NSImageCell NSScaleToFit and Copying

On Panther and earlier, an NSImageCell set to NSScaleToFit mode would always make a copy of its assigned image, even when the NSImageCell was sized such that the image would be displayed at exactly its original size. On Tiger, NSImageCell only makes this copy when the image is being displayed at some size other than its exact original size.


NSWorkspace Custom Icon Setting API

NSWorkspace has a new -setIcon:forFile:options: method that creates an icon from a given image and assigns it as the custom icon of a given file or folder:
- (BOOL)setIcon:(NSImage *)image forFile:(NSString *)fullPath options:(unsigned)options;
The "image" parameter specifies an arbitrary image, with or without transparency information (alpha), that will be automatically rescaled to generate the icon's representations. "fullPath" must specify an existing file or folder to which the user has write permissions. The "options" parameter is a bitwise combination of the following flags declared in NSWorkspace.h (it may be zero):
typedef unsigned int NSWorkspaceIconCreationOptions;
enum {
NSExcludeQuickDrawElementsIconCreationOption = 1 << 1,
NSExclude10_4ElementsIconCreationOption = 1 << 2
};
The option flags provide control over the kinds of representations the custom icon will contain.

The "QuickDraw" format allows for icon representations up to 128x128 pixels, and is supported on Mac OS X 10.0 through 10.4.

Mac OS X 10.4 supplements this with a new class of icon representation, designed to support higher resolutions with better storage efficiency. Finder on Mac OS X 10.4 does not yet make use of icons in this new format, but support for generating them is being provided in the -setIcon:forFile:options: API for forward compatibility. This new icon representation is safely ignored by Finder on Mac OS X 10.3, but its presence will prevent display of the file's custom icon on pre-10.3 systems, even if representations in the "QuickDraw" format are also present. Due to this compatibility issue, and to avoid needlessly consuming additional storage, it is recommended that applications that use the -setIcon:forFile:options: API suppress generation of this new representation, pending its use by a future release of the system.

NSExclude10_4ElementsIconCreationOption suppresses generation of representations in the new compressed high-resolution format. NSExcludeQuickDrawElementsIconCreationOption suppresses generation of the QuickDraw-format representations that are understood and used by Mac OS X 10.0 through 10.4. When neither flag is specified, the behavior will be to generate representations in both formats, resulting in a file or folder whose custom icon will be displayable on Mac OS X 10.3 and 10.4.


NSWorkspace (Section added since WWDC)

If the method fullPathForApplication: failed to find an application using the standard LaunchServices database, it would fall back to doing a world-search in the standard places where applications many be found. In practice though the LaunchServices database does include those places, so a brute force search through these just makes the method call considerably slower.

For apps linked on Tiger, this method will no longer do this secondary search.

The method selectFile:inFileViewerRootedAtPath: now consults a user default named "NSFileViewer", and if present, uses it as the bundle ID of the application to use as the file viewer to select the file in. If this default is not set, or there is no corresponding registered application, then Finder is used as normal. selectFile:inFileViewerRootedAtPath: is the method applications should use for "Reveal in Finder" functionality.

Since 10.0, the method getInfoForFile:application:type has been behaving differently than documented. The documentation claimed that the returned type is actually not the file type but one of a small set of predetermined identifiers indicating the kind of file; it turns out this method actually returned the type of the document. In Tiger, we continue with this preexisting behavior; the documentation will be fixed. The other documentation claim, that this method will return NO if the file doesn't exist, is true only when application info is asked for (argument to application: is non-NULL). So this method will return NO only if app info is asked for, and either the file doesn't exist, or LaunchServices does not have an application association for the document.

The NSWorkspaceDidUnmountNotification notification could be sent even for unsuccessful unmount attempts. It is now sent only if the volume is actually unmounted.


NSColor (Section added since WWDC)

Calibrated NSColors (those created with colorWithCalibratedRed:.., colorWithCalibratedHue:.., or colorWithCalibratedWhite:...) now use Quartz generic color spaces, rather than the "display" (aka "device") color spaces. For debugging purposes this behavior can be disabled with the NSUseGenericColorSpaceForCalibrated default. This is a debugging default and will be removed in a future update.

In applications, the proper way to get the device color space behavior is to create colors with colorWithDeviceRed:..., colorWithDeviceWhite:..., etc.

In many cases, as appropriate, the underlying color for NSColors representing colors used in the user interface (for instance, methods such as -[NSColor alternateSelectedControlColor]) has been changed to device color space.


NSColorSpace (Section added since WWDC)

A new class, NSColorSpace, along with new API in NSColor, enables creating NSColor instances which refer to custom color spaces, including those created with ColorSync profiles.

You can create NSColorSpace instances from CMProfileRef instances or NSDatas containing ICC profile data:
- (id)initWithICCProfileData:(NSData *)iccData;
- (id)initWithColorSyncProfile:(void * /* CMProfileRef */)prof;
- (NSData *)ICCProfileData;
- (void * /* CMProfileRef */)colorSyncProfile;
You can query the characteristics of color spaces with:
- (int)numberOfColorComponents;       // Does not include alpha
- (NSColorSpaceModel)colorSpaceModel;
- (NSString *)localizedName; // Will return nil if no localized name
NSColorSpace is intended to be toll-free bridge to CGColorSpaceRef. But this has not been implemented in Tiger.

Note that the existing "color space" concept, where a small number of predefined color spaces are identified by their names, should not be confused with this new NSColorSpace class. Different types of NSColors have traditionally been distinguished by their "color space" (represented by colorSpaceName). This color space determines the primitive accessors for the color, and in general NSColor instances with different colorspaces do not compare equal; NSColor instances in the same colorspace compare equal if all their attributes are equal.

Existing color space names supported by NSColor are NSCalibratedWhiteColorSpace, NSCalibratedRGBColorSpace, NSDeviceWhiteColorSpace, NSDeviceRGBColorSpace , NSDeviceCMYKColorSpace, NSNamedColorSpace, and NSPatternColorSpace. NSColorSpace provides class methods to return instances which correspond to the applicable predefined color space names:
+ (NSColorSpace *)genericRGBColorSpace;   // NSColorSpace corresponding to Cocoa colorspace name NSCalibratedRGBColorSpace
+ (NSColorSpace *)genericGrayColorSpace; // NSColorSpace corresponding to Cocoa colorspace name NSCalibratedWhiteColorSpace
+ (NSColorSpace *)genericCMYKColorSpace;
+ (NSColorSpace *)deviceRGBColorSpace; // NSColorSpace corresponding to Cocoa colorspace name NSDeviceRGBColorSpace
+ (NSColorSpace *)deviceGrayColorSpace; // NSColorSpace corresponding to Cocoa colorspace name NSDeviceWhiteColorSpace
+ (NSColorSpace *)deviceCMYKColorSpace; // NSColorSpace corresponding to Cocoa colorspace name NSDeviceCMYKColorSpace
In order to support custom NSColorSpaces, we enable creating NSColors with the color space name "NSCustomColorSpace". Such colors are created with:
/* Create colors with arbitrary color space. The number of components in the provided array should match
the number dictated by the specified color space, plus one for alpha (1.0 for opaque colors);
otherwise an exception will be raised. If the color space is one which cannot be used with NSColors, nil is returned.
*/
+ (NSColor *)colorWithColorSpace:(NSColorSpace *)space components:(const float *)components count:(int)numberOfComponents;
and the attributes of such colors are accessed with:
/* For colors with custom color space; get the color space and individual floating point components, including alpha.
Note that all these methods will work for other NSColors which have floating point components.
They will raise exceptions otherwise, like other existing color space-specific methods.
*/
- (NSColorSpace *)colorSpace;
- (int)numberOfComponents;
- (void)getComponents:(float *)components;
One additional API added to NSColor allows converting colors between color spaces:
/* colorUsingColorSpace: will convert existing color to a new color space and create a new color,
which will likely have different component values but look the same. It will return the same color
if the color space is already the same as the one specified. Will return nil if conversion is not possible.
*/
- (NSColor *)colorUsingColorSpace:(NSColorSpace *)space;
colorUsingColorSpace: and the three methods above work not only on NSCustomColorSpace colors, but also on other floating component-based colors. Note that colorUsingColorSpace: does not guarantee to return a NSCustomColorSpace color; for instance, if -[NSColor colorUsingColorSpace:[NSColorSpace genericRGBColorSpace]] is sent to a NSCalibratedRGBColorSpace color, the same color might very well be returned. Of course such a color will respond with NSColorSpace genericRGBColorSpace] for its colorSpace, so the result is not that unexpected.

The existing method colorUsingColorSpaceName: is still the sure way to get a color with a certain colorSpaceName for another color (or nil if the conversion is not possible).

When colors with custom color spaces are archived into old (non-keyed) archives, the assumption is that such archives still need to be read on pre-Tiger systems, so the colors are written in a pre-Tiger compatible fashion, by being converted to one of the named colorspaces, without the NSColorSpace instance. it's possible to override this behavior with the NSWriteCustomColorSpacesToOldArchives default; setting this to YES means that custom color spaces will be written to non-keyed archives, making them incompatible with pre-Tiger systems.


NSColorWell (Section added since WWDC)

Removing a NSColorWell from its window now deactivates the color well.


NSColorList (Section added since WWDC)

Non-editable color lists (identified by isEditable returning NO) now raise exceptions when an attempt is made to modify them. This is as documented.


Accessibility Changes

The following method was added:
- (BOOL)accessibilitySetOverrideValue:(id)value forAttribute:(NSString *)attribute;
It allows you to override the value of an attribute or add a new attribute to a particular UI Element – i.e. an instance of NSObject conforming to the the NSAccessibility protocol. Previously, the only way to accomplish this was to use a custom a subclass for that UI Element and override the appropriate NSAccessibility protocol methods – e.g. accessibilityAttributeValue.

• This method only works on objects whose class already implements the NSAccessibility protocol.

• The return value indicates if the attempt to override was successful.

• If the specified attribute is already supported by the object, the value you specified wins - i.e. for this instance it will override the attribute value that would have been returned otherwise. This is done outside the NSAccessibility protocol – accessibilityAttributeValue won't get called when determining an overridden attribute's value.

• If the specified attribute does not exist it will be created. This is done outside the NSAccessibility protocol – accessibilityAttributeNames will still return the old list which does not contain the new attribute.

• Once again, overriding attributes is done outside the NSAccessibility protocol. Accessing attributes using accessibilityAttributeNames and accessibilityAttributeValue will not return attributes created by the override process nor will it return their overridden values.

• Overridden attributes are not settable. I.e. accessibilitySetValue:forAttribute will never be invoked for an overridden attribute. If you override a settable attribute it will no longer be settable. What's being referred to here is the ability of the assistive app to change the attribute's value. Calling accessibilitySetOverrideValue:forAttribute again will change the overridden value.

• The method, accessibilitySetOverrideValue:forAttribute:, should not be confused with accessibilitySetValue:forAttribute:. The latter method, which is a part of the NSAccessibility protocol, is invoked when an assistive application wants to change the value of an attribute - e.g. alter the setting of a slider.

• If you need to undo the effect of using this method, call it again passing nil for the value.

• You need to ensure you invoke this method on the actual object that represents the UI Element. E.g. in the case of NSButton you'd need to use the underlying NSButtonCell. The NSButton itself is ignored by accessibility. If you're unfamiliar with this concept see the documentation for the accessibilityIsIgnored method of the NSAccessibility protocol.

• This method works on an object representing a single UI Element. When there is no object underlying a UI Element then you won't be able to use it. A common case where this is a problem is when a single object represents multiple UI Elements (e.g. NSSegmentedCell has only a single object but it provides UI Elements for each segment).
NSString *NSAccessibilityRoleDescription(NSString *role, NSString *subrole);
NSString *NSAccessibilityRoleDescriptionForUIElement(id element);
NSString *NSAccessibilityActionDescription(NSString *action);
These functions were added to help with implementing the accessibility protocol – specifically for returning descriptions of standard roles and actions. E.g. if you implement a button widget that does not inherit from NSButton you should use NSAccessibilityRoleDescription to return a localized role description matching what is returned by standard buttons.

• You should pass nil to NSAccessibilityRoleDescription if there is no sub-role.
• NSAccessibilityRoleDescriptionForUIElement is like NSAccessibilityRoleDescription, but it queries the element to get the role and sub-role. Obviously, NSAccessibilityRoleDescription is more efficient, but this function is useful for accessorizing base classes so that they properly handle derived classes – which may override the sub-role – or even the role.


NSOpenGL Pixel Format Attributes

Four new pixel format attribute constants have been added to NSOpenGL.h, to expose new framebuffer options provided by CGL.
NSOpenGLPFAColorFloat         =  58, /* color buffers store floating point pixels    */
NSOpenGLPFAMultisample = 59, /* choose multisampling */
NSOpenGLPFASupersample = 60, /* choose supersampling */
NSOpenGLPFASampleAlpha = 61, /* request alpha filtering */
See the OpenGL release notes for information regarding the correct usage of these features.


Services (Section added since WWDC)

In previous releases, AppKit's deferred Services menu building until the first time an application's menu was accessed. This produced a slight delay in the first menu pull-down, while making the key equivalent shortcuts for Services menu items unusable until the Services menu had been built. Both issues have been fixed in Tiger, making key equivalents for Services menu items usable immediately after app launch, while deferring initialization of the Services menu until it is actually needed.

In Tiger, the Services facility names the communication ports that it uses based on the service provider's bundle identifier. (On previous releases, the process name was used instead.) This change in naming convention will be invisible to most service providers and clients. However, a ".service" bundle can optionally declare services that are provided by another bundle's executable, instead of containing its own executable. In such cases, the bundle that declares the service must specify the provider's bundle identifier as the service's NSPortName, to enable the Services facility to find and (if necessary) launch the provider. The provider bundle can be an ".app" bundle, or a ".service" bundle that has its own executable.


Bug Fix in Handling of NSURLPboardType (Section added since WWDC)

A bug was introduced in Mac OS 10.3 that sometimes prevented NSURLPboardType data from appearing on pasteboards provided by Carbon programs. For example, the invocation of +[NSURL URLFromPasteboard:] in the CocoaDragAndDrop example would incorrectly return nil when an image file was dragged from the Finder and dropped on one of the program's DragDropImageViews. This bug has been fixed.


Delegation and Notification warning (Section added since WWDC)

With AppKit classes which provide delegation and notification (such as NSWindow), if you explicitly register for certain notifications which are also used to send delegate messages, and then you stop being a delegate, you are unregistered for those notifications. It's not clear how this will be addressed in the future, but you should be aware of this potentially unexpected behavior.


Alert panel in Java

Bug where occurrences of "%" would disappear in alert panels in Cocoa Java applications has been fixed for applications linked on Tiger or later. A workaround for earlier applications is to double each "%" that occurs in the message string.





Notes specific to Mac OS X 10.3

Aqua Refinements

Panther brings along a bunch of Aqua refinements, which are meant to enhance the look of applications compatibly, without needing any changes to the applications. The changes to user interface elements preserve layout metrics, which helps maintain compatibility. Where appropriate, return values of various APIs (for instance, NSColors) have been changed to support the new look; applications using these APIs will get the new values automatically.


Mini controls

A number of controls now support a control size NSMiniControlSize that is smaller than NSSmallControlSize. The controls that draw with this size are: radio buttons, checkboxes, push buttons, sliders, tab views, steppers, popup and pulldown menus, and comboboxes. Rounded text fields and search fields can now be sized smaller and will use a smaller rounded bezel depending on the height of the text field. NSStepperCell now supports both small and mini sizes. Mini-controls are designed to be used with LucidaGrande 9 pt as the text font.


Bindings (aka Controller Layer)

A major new feature in Cocoa for Panther is the ability to bind UI objects to model objects through controllers. This technology allows Cocoa developers to get much more application implementation done directly in Interface Builder.

The controller layer technology is based in the Model-View-Controller (MVC) design paradigm. Cocoa provides a rich set of view and model classes, but until now there was no powerful and generalized controller functionality. With the new controller layer, Cocoa developers finally have API level and Interface Builder level support for binding display values and characteristics of an application's UI to data held in the application's data model. Via the controller layer, data values and changes can be propagated live between UI elements and the application's data storage without developers having to write all of the glue code they had to before.

In Interface Builder, check out the Controllers palette for NSController classes that can be added to new and existing nibs. These controllers add functionality like selection tracking, propagating edits in the user interface, sorting, and handling input validation. The logic built into the NSUserDefaultsController, NSObjectController, and NSArrayController, which are provided to you by default, allow you to focus on designing the data model and user interface without having to write excessive amounts of glue code to get to a polished application. The controller classes provide the glue logic for you.

In Interface Builder, there is also a new inspector item: the Bindings Inspector. This inspector allows you to bind user interface elements like NSTextField, NSTableView, NSImageView, and NSTabView, to NSController instances in your nib (or controller instances to other controllers). This way you don't have to explicitly make outlet connections to your NSDocument or NSApplication file's owner. Various properties of the widgets (such as the source of a NSTextField's value, or the font and text color of the text field) can be controlled through a controller.

Relevant header files for this technology include <AppKit/NSKeyValueBinding.h>, <AppKit/NSController.h>, <AppKit/NSArrayController.h>, <AppKit/NSObjectController.h>, and <AppKit/NSUserDefaultsController.h>.

Key value coding has also been enhanced to support the bindings technology. Please refer to <Foundation/NSKeyValueCoding.h> and <Foundation/NSKeyValueObserving.h> for more information.

Note that nib files using the new controller layer (instances of NSController subclasses and bindings) can only be loaded and saved on the "10.2 and later" nib file format. Nib files in older formats have to be converted by opening them in Interface Builder and explicitly saving them in the new format.

Also, nib files created with pre-releases of Mac OS X 10.3 may contain bindings that are not legal in the GM release. Those bindings typically result in key-value coding exceptions ("undefined key") at runtime and show up in the "Parameters" section of the Bindings inspector in Interface Builder. You should disconnect the bindings manually and replace them with a new binding (which is usually obvious to pick).

Bindings for menu items and other objects that auto-validate the enabled state (like toolbar items) are ignored unless auto-validation is turned off (in the NSMenu - which can be done in Interface Builder). For example, a menu item with a value binding, but no target/action set, will always be disabled unless auto-validation is turned off manually.

NSControllers ignore the options that can be passed to the -addObserver:forKeyPath:options:context:context: method. So even if you register observers with the NSKeyValueObservingOptionNew or NSKeyValueObservingOptionOld options, you will not receive the values in the change dictionary of the -observeValueForKeyPath:ofObject:change:context: calls. This is usually not a problem, but if you rely on receiving those values, a workaround may be to observe the model objects directly.



NSAlert

We added NSAlert as a new public class. This class provides the functionality previously available only through NSPanel C-based functions, and builds flexibility on top of that functionality. For example, it is now possible to specify a custom icon and assign application specific key equivalents or return values to the NSAlert buttons. It is also possible to use more than three buttons, although this should be done only when strictly necessary. We have also added API for inclusion of a help button on the alert panel.

This API can be used for both modal panels and sheets.

Note that by default, the new return values --- NSAlertFirstButtonReturn, etc --- are easier to use and more flexible, but are not the same as the previous values --- NSAlertDefaultReturn, etc. This is an important point, as your alert return handlers will change behavior if you move your code over without paying attention to this. The following convenience method can be used for easy migration from uses of the C-based APIs, as it sets up compatible return values:
+ (NSAlert *)alertWithMessageText:(NSString *)message
defaultButton:(NSString *)defaultButton
alternateButton:(NSString *)alternateButton
otherButton:(NSString *)otherButton
informativeTextWithFormat:(NSString *)format, ...;
The return values can be customized with the setTag: methods, whose use in the alert panel is reserved for this purpose.

Note that the alert panel also reserves the use of the target and the action.

Please refer to documentation for more detailed info on this new class.


NSSpeechRecognizer / NSSpeechSynthesizer

NSSpeechRecognizer and NSSpeechSynthesizer are two new AppKit classes which provide access to Mac OS X's speech capabilities. There are examples of these classes in use in /Developer/Examples/Speech. In addition, documentation for these classes is available in the Application Kit reference.


NSShadow

NSShadow is a new AppKit class, created for the purpose of holding the parameters of a drop shadow to be used when drawing. Shadows are always drawn in base space (also known as default user space). This means that rotations, translations and so on of the current transformation matrix (the CTM) don't affect the resulting shadow. Another way to think about this is that changes to the CTM don't move or change the light source.

There are two positional parameters for a shadow, an x-offset and a y-offset of the shadow, expressed as a single NSSize, in default user space units, with positive values being up and to the right. There is one additional floating-point parameter, the blur radius, which specifies how much an object's image mask is blurred before it is composited onto the destination. A zero value means no blur, and larger values give correspondingly larger blurs, again in default user space units.

In addition, a shadow may have a color. If no color is set, then the shadow will be drawn using black with an alpha value of 1/3. If a color is set, then the shadow will be drawn using that color. Currently only colors convertible to RGBA are supported.

An NSShadow may currently be used in one of two ways. First, it may be set, like a color or a font, in which case it is applied to all drawing until another shadow is applied or until the next graphics state restore. It may also be used as the value for the new NSShadowAttributeName text attribute, in which case it will be applied to the glyphs corresponding to the characters bearing this attribute. See the section on additional text attributes for the definition of NSShadowAttributeName.


NSNib

NSNib is a new AppKit class representing a nib file. When an NSNib instance is created from a nib file, all of the data needed to instantiate the nib (the object graph as well as images and sounds that might be in the nib bundle) are read from the disk, however the nib is not instantiated until you call one of the instantiation methods. You can use NSNib to quickly reinstantiate a frequently accessed nib file, without loading the nib repeatedly from disk.



NSSegmentedControl, NSSegmentedCell

NSSegmentedControl is a new control that implements a multi-part cell or 'segment' view. Each segment can contain an image, plain label, menu, tag, and tooltip. The segments are autosized unless a specific width is set. The class provides three tracking modes: Radio-like (NSSegmentSwitchTrackingSelectOne), toggling (NSSegmentSwitchTrackingSelectAny), and push-button (NSSegmentSwitchTrackingMomentary).

NSSegmentedControl is a pass through for most of the calls to its cell. It also handles keyboard UI. NSSegmentedCell can be placed inside a matrix though usually it's inside an NSSegmentedControl.

Please refer to documentation for more info on these two classes.

(As an aside, this was the control for which we asked for naming suggestions during WWDC 2003. Many thanks for your cards and letters --- we got hundreds of suggestions!)


NSSearchField and NSSearchFieldCell

New subclasses of NSTextField and NSTextFieldCell have been added that create a standard UI for search fields like the ones in Mail, Safari, and Address Book. This includes a cancel button, search button with menu and the option to send the results while typing or when the user presses return. API for NSSearchField is minimal and forwards to NSSearchFieldCell. You should set the target and action of this control or its cell to the receiver that is interested in the search request. The border is a round text field.

Please refer to documentation for more info on these two classes.


NSSlider

A new style of slider called a circular slider (i.e. dial) is available. You can get it by setting the slider type. You then get a fixed sized slider that goes from minValue to maxValue. minValue is at the top and the value increases as you rotate clockwise to just below maxValue (e.g. if you set min = 0, max = 360, you can get to 359.999). You can show tick marks and have values limited to just the tick marks the same as a regular slider. You can only have regular and small. There is no mini version.
typedef enum {
NSLinearSlider = 0,
NSCircularSlider
} NSSliderType;
- (void)setSliderType:(NSSliderType)sliderType;
- (NSSliderType)sliderType;

New NSOpenPanel / NSSavePanel

Panther features a new user interface for open and save panels, while maintaining compatibility with the existing APIs.

Due to the changes in the panel, the following constants (view tags) are no longer supported. The last three were already marked in NSSavePanel.h as deprecated:
NSFileHandlingPanelImageButton
NSFileHandlingPanelTitleField
NSFileHandlingPanelBrowser
NSFileHandlingPanelForm
NSFileHandlingPanelHomeButton
NSFileHandlingPanelDiskButton
NSFileHandlingPanelDiskEjectButton
Added the following getter methods to match the existing setter methods:
- (id)delegate;                // - (void)setDelegate:(id)delegate;
- (BOOL)canSelectHiddenExtension;    // - (void)setCanSelectHiddenExtension:(BOOL)flag;
Added the following delegate methods to allow accessory views to keep in sync with changes in the state of the panel:
- (void)panel:(id)sender directoryDidChange:(NSString *)path;
- (void)panelSelectionDidChange:(id)sender;
Two methods have been added to allow providing a short message at the top of the panel:
- (NSString *)message;
- (void)setMessage:(NSString *)message;
In Jaguar, the methods directory, filename, and URL were usable only after the panel was dismissed – and documented as so. This restriction has been lifted in Panther.

The use of -selectText: is deprecated. This method no longer does anything.

One known incompatibility is with applications which messaged the panel after it was released. This often worked before. If you notice that an application crashes after using the open or save panels, you can, as a debugging or temporary measure, set the NSDelayedSavePanelDeallocation user default to YES, which should avoid the problem. This default will be removed in the future.


NSSavePanel

Two methods have been added to NSSavePanel to support changing the label next to the filename edit field - which is normally labelled "Save as:":
- (NSString *)nameFieldLabel;
- (void)setNameFieldLabel:(NSString *)label;
In Jaguar we supported a single required file type with the methods setRequiredFileType and requiredFileType. We now support a list of types:
- (NSArray *)allowedFileTypes;
- (void)setAllowedFileTypes:(NSArray *)types;
The old and new calls interact as follows. Calling setRequiredFileType: is equivalent to calling setAllowedFileTypes: with an array of that one type. Calling requiredFileType will return the first element of the list of allowed types or nil if there are none. As was the case with setRequiredFileType: nil, setAllowedFileTypes:nil means allow any file type. Calling setAllowedFileTypes: with the empty array is not allowed.

In Jaguar, if a user tried to use a filename with a recognized extension that did not match the required type they were given three options: cancel, replace their extension with the required one, or use both (e.g. foo.html.txt). There was no option to use the specified extension. Apps that needed to provide this option (e.g. TextEdit and Safari, so you could use .h or a .html as an alternative to .txt) had special code to work around this limitation.

To address this there are two new methods:
- (BOOL)allowsOtherFileTypes;
- (void)setAllowsOtherFileTypes:(BOOL)flag;
As was the case in Jaguar, if the user tries to save a filename with a recognized extension that's not in the list of allowed types they will be presented with a dialog. However, if allowsOtherFileTypes is YES, then the dialog will present the option of using the extension the user specified. The default setting for allowsOtherFileTypes is NO, otherwise existing applications would start getting extensions they are not prepared to handle.



NSOpenPanel

The following new NSOpenPanel method allows modeless operation of the open panel:
- (void)beginForDirectory:(NSString *)path
file:(NSString *)name
types:(NSArray *)fileTypes
modelessDelegate:(id)delegate
didEndSelector:(SEL)didEndSelector
contextInfo:(void *)contextInfo;
Two methods have been added to allow open panels to have a "New Folder" button - which may be useful in open panels configured to allow folder selection:
- (void)setCanCreateDirectories:(BOOL)flag;
- (BOOL)canCreateDirectories;

NSMenu

NSMenuItems which have submenus now can have a target and action set and the item itself will be selectable. Calling -[NSMenuItem setSubmenu:] will no longer modify the action if it isn't NULL or @selector(submenuAction:). You can turn it off again by setting the action of the item to either NULL or @selector(submenuAction:).

Menubar items will now display an image if you set it.

NSMenuItem has some new setter/getter API to add functionality found in Carbon menus:
- (void)setAlternate:(BOOL)isAlternate;
- (BOOL)isAlternate;
This marks the item as an alternate to the previous menu item. If the item has the same key equivalent as the previous item but has different key equivalent modifiers then the items will be folded into a single visible item and the appropriate item will show while tracking the menu. You can have items with no key equivalent but different modifiers in which case, the only way to access the alternate items is via the mouse. You can have a number of items marked as alternate though if their key equivalents don't match, they may end up as separately visible items. Marking the first item as an alternate has no effect. This flag is archived.
- (void)setIndentationLevel:(int)indentationLevel;
- (int)indentationLevel;
This sets the menu item indentation level from 0 to 15. Indentation levels greater than 15 are pinned to the maximum. Values less than 0 generate an exception. The default indentation level is 0. This value is archived.

You can now specify the font when displaying a context menu using the class method:
+ (void)popUpContextMenu:(NSMenu *)menu
withEvent:(NSEvent *)event
forView:(NSView *)view
withFont:(NSFont *)font;
Passing in nil for the font uses the default font for menu.

You can pass in a custom string for a menu item by setting an attributed string. This will let you add styled text and an embedded image to a menu item string. If the text color is not set, it will be white on selection and grey on disabled. Any colored text will remain unchanged when higlighted. When you set the attributed title, the regular title is also set with the plain string value but when you clear the attributed string title, the title remains unchanged. This string is not archived in in the old nib format.
- (void)setAttributedTitle:(NSAttributedString*)string;
- (NSAttributedString*)attributedTitle;
You can set a help tag for a menu item. This includes items in the main menu bar. This string is not archived in the old nib format.
- (void)setToolTip:(NSString*)toolTip;
- (NSString*)toolTip;
You can now register for a notification when menu tracking ends even if no action is sent. Register for the notification:
NSString *NSMenuDidEndTrackingNotification;
This notification is sent for the main menu bar ([NSApp mainMenu]) and for the root menu of a popup button.

NSMenu now has a delegate that you can use to populate a menu just before it is going to be drawn and to check for key equivalents without creating a menu item. NSMenu has two new methods:
- (void)setDelegate:(id)anObject;
- (id)delegate;
This delegate is not archived in in the old nib format.

To populate the menu, the delegate should implement either:
- (void)menuNeedsUpdate:(NSMenu*)menu;
Which is called when the menu is about to be displayed at the start of a tracking session. You can change the menu by adding, removing or modifying menu items. Any new items should have the proper enable state set.

Alternatively, if population is going to take some time, you can implement a pair of methods:
- (int)numberOfItemsInMenu:(NSMenu*)menu;
- (BOOL)menu:(NSMenu*)menu updateItem:(NSMenuItem*)item atIndex:(int)index shouldCancel:(BOOL)shouldCancel;
The first method returns the number of items in the menu. If the value returned is positive, the menu is resized by either removing or adding items. If you return a negative value, the number of items is left unchanged and update method is not called. Newly created items are blank. Then the second method is repeatedly called for each item at which time, the menu title, image, etc. can be updated. If during the updating, the user does something so that the menu no longer needs to be displayed, then the shouldCancel paramter will be set to YES. You can ignore the flag or stop updating and save where you left off until the next time.

If the delegate implements the method:
- (BOOL)menuHasKeyEquivalent:(NSMenu*)menu forEvent:(NSEvent*)item target:(id*)target action:(SEL*)action;
This method allows the delegate to return the target and action for a key down event. The method should return YES if there would be a valid and enabled item for the key event and return the target and action (both of which can be nil/ NULL to invoke the menu's target and action). If this method isn't defined in the delegate, the menu will be populated to find out if any items have a matching key equivalent. The delegate should return NO if there are no items with that key equivalent or the item would be disabled.

For applications built on Panther or later, menu tracking will now run the runloop in NSEventTrackingRunLoopMode rather than NSDefaultRunLoopMode. This is consistent with tracking in other controls, and fixes a problem where an application could cause menus to get stuck onscreen by intercepting the runloop unexpectedly, eg. by putting up a modal panel while the user was tracking in a menu. This change means that timers and other runloop sources added only for NSDefaultRunLoopMode will not fire during menu tracking. If you want your timer to continue to fire during menu tracking, you should also add it to the runloop for NSEventTrackingRunLoopMode. One easy way to do this is to use kCFRunLoopCommonModes, although that also has the effect of enabling your runloop source while in NSModalPanelRunLoopMode.



Delegation and Notification

With AppKit classes which provide delegation and notification (such as NSWindow), if you explicitly register for certain notifications which are also used to send delegate messages, and then you stop being a delegate, you are unregistered for those notifications. It's not clear how this will be addressed in the future, but you should be aware of this potentially unexpected behavior.


NSColor

You can determine the current system control tint when rendering colors by using the NSColor class method.
+ (NSControlTint)currentControlTint;
This method will currently return either NSBlueControlTint or NSGraphiteControlTint.

The method selectedMenuItemColor now returns a pattern image based on the current appearance (blue or graphite) rather than a solid color.

-[NSColor set] no longer strips the transparency when the output is going to a device other than the screen (for instance, printer or file). Note that this change was introduced in Jaguar software update 10.2.3; and it is active only for applications linked on 10.2 or later. However, an app can choose to force the behavior one way or the other by registering the default NSAllowTransparencyWhenPrinting with YES or NO.

+[NSColor disabledControlTextColor] now returns 50% white rather than 53% white.

It is now possible to set the fill and stroke colors independently with NSColor, with the setFill and setStroke methods. The set method continues to set both. Going forward, all three should be treated as primitives --- that is, methods that need to be implemented by subclassers. For compatibility, there are implementations of setFill and setColor in NSColor, but they work by converting the color to RGB and filling or stroking it.

NSColor has introduced a new method which returns the standard list of alternating colors used by many applications, such as iTunes. NSTableView has added straightforward support for drawing its background using these colors. However, those implementing a custom row based controls may use this new API to draw an alternating background:
+ (NSArray *)controlAlternatingRowBackgroundColors;

NSColorPanel

The color panel can now display arbitrary copyright information for a color list. To provide copyright information, simply add the NSColorListCopyrightInfo key to your color lists strings file (eg. MyColorList.clr/English.lproj/MyColorList.strings).


NSColorWell

Prior to Panther, sometimes just clicking on a color well would cause its action to be sent. This has been fixed. NSColorWell now only sends its action if the color it's holding has indeed changed.

Calling activate: programatically now correctly shows the color panel if it is already not visible.


NSImage

The issue where rendering an NSImage into another lockFocus'ed NSImage could wipe out the graphics state is fixed.

The limitation on the size of an NSCachedImageRep and thus an NSImage that you -lockFocus on has been raised from 10,000 to 32,767. Note that you images below this size may still fail because of memory limitations.


NSImageRep

The NSImageRepRegistryDidChangeNotification now contains the actual NSImageRep class that was added or removed instead of the receiver of the message, which was usually the base NSImageRep class.


NSBitmapImageRep

You can now read and write 5 channel CMYKA images.

If an animated GIF image contains information specifying the number of times to play the GIF, a new property is available as a read-only value.
NSString* NSImageLoopCount;
If set, the extension had an explicit value specified. The loop count value will be between 0 and 65,535 with a value of 0 meaning loop forever. If the property is not present, it was not specified in the file and it will be up to the app to decide how many times to loop

PNG files now have the correct size and DPI set based in the 'pHYs' chunk in the file. This only applies to applications compiled after Jaguar (10.2.x).


NSImageView


NSImageView instances can now automatically play back animated GIF images. This functionality is controlled by the new accessor API:
- (void)setAnimates:(BOOL)flag;
- (BOOL)animates;
An NSImageView whose "animates" property is set to YES will automatically play any animated image that is assigned to it, with the timing and looping characteristics specified by the image data. When "animates" is set to NO, the NSImageView displays the first frame of the animation (consistent with the behavior on Jaguar and earlier). The default is YES for newly created NSImageView instances, NO for previously created NSImageView objects loaded from .nib files.

This setting does not affect the display of ordinary still images.

Applications wanting more control over animation playback can use NSBitmapImageRep's animated image functionality to directly access the animation's individual frames and timing data.


NSView

On Jaguar and earlier, areas of a view that are marked dirty using -setNeedsDisplayInRect: are coalesced (via an NSUnionRect() operation) into a single "dirtyRect" that the view maintains. The drawing thus scheduled is done later at the end of the run loop cycle, when invalidated areas are propagated as needed to each view's ancestors and descendants and -drawRect: is invoked for each view that needs to draw some or all of its contents.

In addition to requiring redrawing of more of a view's area than may be strictly necessary, this "coalescing" of invalidated rectangles into a single rectangle per view had the side effect of sometimes causing invalidation of otherwise "clean" views and view subtrees that happen to share a common container view (e.g. parent NSBox or NSView). An application's susceptibility to this problem depends on its UI layout and invalidation patterns.

On Panther, we maintain a more detailed representation of the invalidated parts of views that enables us to better avoid this problem. Applications automatically inherit most of the benefits of this enhancement automatically. However, there is also new API provided for implementors of NSView subclasses that wish to take advantage of the more detailed dirty area information that is now available to them.

-drawRect: remains the overridable "draw self" callback for view classes. However, the implementor of -drawRect: can now call back to self to request a more detailed description of the area to be drawn than the single NSRect parameter to -drawRect: provides. Specifically, one can request a list of rectangles that more closely approximates the area that needs drawing, via the new method:
- (void)getRectsBeingDrawn:(const NSRect **)rects count:(int *)count;
On return from this method, *rects contains a pointer to the list of NSRect values, and *count is the number of rectangles in the list. Depending on its drawing strategy, a -drawRect: implementation can inspect this list directly to determine what to draw, or it can use the convenience method:
- (BOOL)needsToDrawRect:(NSRect)aRect;
to test individual objects to be drawn one at a time against the list. -needsToDrawRect: returns YES if aRect intersects any of the rectangles in the list, NO otherwise. Use of this convenience method would be appropriate for a view that determines what to draw by simply iterating over a list or hierarchy of drawable objects. A view that can efficiently determine which of its elements needs to be drawn as a function of a given rectangle (such as a view that displays an image or images, or a regular grid of objects) may be better suited to inspecting the rect list directly. Note that the NSRect parameter that -drawRect: receives remains potentially useful as an overall bounding rectangle surrounding the area to be drawn. Intersection tests against this rectangle can be performed as a quick "trivial rejection" test, identifying objects that are clearly outside the area to be drawn. -needsToDrawRect: uses this strategy in its implementation.

To guarantee compatible drawing behavior for existing view classes, AppKit by default enforces clipping to the area that needs drawing. On Jaguar and earlier, clipping was enforced more loosely to the NSRect parameter of -drawRect:.

A view that does not want the default, AppKit-provided clipping (either because its -drawRect: implementation is very careful to draw only within the requested area, or because it sets up its own clipping) can refuse the default clipping by overriding the new -wantsDefaultClipping method to return NO:
- (BOOL)wantsDefaultClipping;
The default implementation provided by NSView returns YES. Any view that returns NO for this method is responsible for setting up its own clipping, or for otherwise insuring that it does not draw outside the requested area. The view will inherit only whatever clipping is provided by its nearest ancestor that does not itself forego the default AppKit-provided clipping.


NSView has new API that allows for hiding individual views or entire view subtrees. A hidden view remains in its superview's list of subviews and participates in autoresizing, but is not displayed and does not receive input events. This facilitates replacing the old technique of removing a view from its superview in order to "hide" it, while avoiding the loss of autoresizing functionality from which that approach has always suffered.

Hiding of views is controlled by the following new NSView methods:
- (void)setHidden:(BOOL)flag;
- (BOOL)isHidden;
- (BOOL)isHiddenOrHasHiddenAncestor;
To hide a view, you send it the message -setHidden:YES. AppKit will mark the area the view occupies in its superview as needing display, and since the view is now hidden it will not be drawn when the next drawing pass happens, so the view will disappear. Any cursor rects, tooltip rects, or tracking rects that the view owns will be disabled during the time the view is hidden.

If a view that has subviews is hidden, its subviews and their descendants will be effectively hidden as well, with the same consequences applying to their cursor/tooltip/tracking rects and ability to receive input events. Note however that -isHidden only returns YES for a view that has itself been explicitly hidden via the -setHidden: API. To ask the broader question of whether a view has become effectively hidden, whether by being explicitly hidden itself or as a consequence of having an ancestor that is now hidden, send the view an -isHiddenOrHasHiddenAncestor message.

If a -setHidden:YES message causes the view that is the window's current firstResponder to become effectively hidden, the nextValidKeyView is made the new first responder. A hidden view remains in the nextKeyView chain it was previously a part of, but is ignored for purposes of keyboard navigation.

To restore a hidden view, send it the message -setHidden:NO. Unless the view remains effectively hidden due to having a hidden ancestor view, AppKit will cause it to again be shown, and will restore any cursor rects, tooltip rects, and tracking rects that it owns.


On MacOS X versions prior to Panther, if an NSView's bounds are changed (via one of the -setBounds...: methods), the receiving view's ability to autoresize subviews is permanently disabled. An example of this behavior can be seen in TextEdit on Jaguar. If you enable "Format-->Wrap To Page" and then set the magnification to anything (even 100%), the NSClipView's bounds are set. If you then convert back to "Wrap to Window" mode, the NSClipView no longer automatically resizes its subviews -- stretching the window will reveal that the NSTextView is not automatically resized.

When bounds are set on an NSView, it creates a transform matrix to adjust view drawing. Since this transform matrix can result in a rotated view, the rules for knowing how to autoresize a subview are unknown, thus NSView simply turns off that behavior.

For applications linked on Panther, this behavior has been adjusted so that if the transform matrix is effectively returned to the "identity" matrix (no warping) autoresize subviews behavior becomes enabled again.


You can ask a view if it should become the key view based on the current keyboard UI mode (all controls/text field only). You should not override this method. Use -[NSView acceptsFirstResponder] for that case.
- (BOOL)canBecomeKeyView;

NSView / NSCell - Focus Ring Drawing API

NSView and NSCell have introduced API which allows developers to control focus ring drawing. Specifically, you can disable a view's focus ring drawing by overriding -focusRingType, or calling -setFocusRingType: with NSFocusRingTypeNone. You should only disable a view from drawing its focus ring in limited situations. Typically you might do so because you want to draw your own focus ring, or because there isn't sufficient space to display a focus ring in the default location. This setting is archived in old and new style nibs.


NSCell

If you set the object value of a cell with a class that responds to the selector -attributedStringValue, then the cell will use that method to fetch the string to draw rather than using -stringValue.

Control tint numbers for the blue (NSBlueControlTint) and graphite (NSGraphiteControlTint) tints have been added to the NSControlTint enum. You can use these in conjunction with +[NSColor currentControlTint] to determine the color to render your custom controls.

NSMiniControlSize, a new size of control that is smaller than NSSmallControlSize has been added to the NSControlSize enum. NSCell and its subclasses and NSProgressIndicator, NSScroller, and NSTabView will accept this new size.


NSButtonCell

Calling -[NSButtonCell setImageDimsWhenDisabled:] would be ignored and the image would always render dimmed. It now checks the flag and will not dim the image if the flag is set to NO.

Several new button bezel styles have been added:

NSTexturedSquareBezelStyle will get you a bezel style to use that is appropriate for textured (metal) windows.

NSDisclosureBezelStyle supports the disclosure triangle like the one in NSOutlineView. You can create the disclosure triangle by setting the button bezel style to NSDisclosureBezelStyle and the button type to NSOnOffButton.

NSHelpButtonBezelStyle has been added to provide the standard help button look.


NSTextFieldCell

New API for NSTextFieldCell allows you to specify a string to draw if the string value of the text field cell is empty and the text field cell isn't editing. This string never appears as the cell's string value but is used at the drawing stages if the actual string value is nil or @"". The plain text string will be drawn in grey. This string is not archived in the old nib format. Setting the attributed string clears out the plain text string and vice versa.
@interface NSTextFieldCell
- (void)setPlaceholderString:(NSString*)string;
- (NSString*)placeholderString;
- (void)setPlaceholderAttributedString:(NSAttributedString*)string;
- (NSAttributedString*)placeholderAttributedString;
@end

NSScrollView

Beginning with Panther, an NSScrollView can be asked to automatically hide its scrollers when they are not needed. Off by default, this behavior can be controlled via the following new API:
- (BOOL)autohidesScrollers;
- (void)setAutohidesScrollers:(BOOL)flag;
Because showing and hiding of its scrollers causes an NSScrollView to retile, use of this feature in contexts where another mechanism competes for control of the document view's size is not recommended. In particular, when a document view's enclosing NSScrollView is set to automatically hide its scrollers, the document view should not be set to autoresize. AppKit will avoid potential recursions that might arise as a result, but this may prevent scroller autohiding from working properly for such views.

A previous empty implementation of -toggleRuler: has been removed from NSScrollView. The stub implementation, which was intended to help ensure compatibility for pre-Mac OS X apps that used a deprecated ruler view class, was removed to prevent it from blocking the responder chain for apps that wished to handle this message.

When using an NSClipView within an NSScrollView (the usual configuration for using an NSClipView), developers should issue messages that control background drawing state to the NSScrollView, rather than messaging the NSClipView directly. This recommendation applies to the following messages:
- (void)setBackgroundColor:(NSColor *)color;
- (NSColor *)backgroundColor;
- (void)setDrawsBackground:(BOOL)flag;
- (BOOL)drawsBackground;
Although NSClipView provides the same set of methods, they are intended primarily for when the NSClipView is used independently of a containing NSScrollView. In the usual case, NSScrollView should be allowed to manage the background-drawing properties of its associated NSClipView.

Previous documentation did not make this clear, but note that there is only one set of background-drawing state per NSScrollView/NSClipView pair. The two objects do not maintain independent and distinct drawsBackground and backgroundColor properties; rather, NSScrollView's accessors for these properties largely defer to the associated NSClipView and allow the NSClipView to maintain the state. In Jaguar and earlier system versions, it may have appeared that an NSScrollView and its NSClipView did maintain separate state for the drawsBackground property, since NSScrollView maintained a cache of the last state it set for its NSClipView that could become out of sync if the NSClipView was sent a setDrawsBackground: message directly. This caching of state has been removed in Panther. However, it remains important to note that sending a setDrawsBackground: message with a parameter of NO to an NSScrollView, rather than directly to its enclosed NSClipView, has the added effect of sending the NSClipView a setCopiesOnScroll: message with a parameter of NO (as documented). The side effect of omitting this step is the appearance of "trails" (vestiges of previous drawing) in the document view as it is scrolled.

Thus the general recommendation is to send requests pertaining to background drawing state to an NSClipView's enclosing NSScrollView (when present) and allow the NSScrollView to manage the NSClipView's state.


NSMovie

If you explicitly create an NSMovie using the -initWithMovie: method, DisposeMovie will no longer be called on the movie when the NSMovie is deallocated. Movies created via a URL or pasteboard will still be disposed. This change will only affect applications compiled in Panther or later.


NSStatusItem

For standard status bar items, you can now set an alternate image that is displayed when the item is highlighted on mouse tracking.
- (void)setAlternateImage:(NSImage*)image;
- (NSImage*)alternateImage;
For custom view status bar items, there are two new methods to help emulate standard items. The first method will draw the menu background pattern in the status item custom view in regular or highlight pattern.
- (void)drawStatusBarBackgroundInRect:(NSRect)rect withHighlight:(BOOL)highlight;
This will display a menu under the custom status item.
- (void)popUpStatusItemMenu:(NSMenu*)menu;

NSOpenGLContext, NSOpenGLPixelFormat

NSOpenGLContext and NSOpenGLPixelFormat have new accessors that you can invoke to obtain the underlying CGL objects. You can then use the CGL API to work with these objects directly.

NSOpenGLContext provides:
- (void *)CGLContextObj;        /* cast the return value to a CGLContextObj */
Similarly, NSOpenGLPixelFormat adds the accessor:
- (void *)CGLPixelFormatObj;    /* cast the return value to a CGLPixelFormatObj */

NSWorkspace

NSWorkspace now has API for opening files and launching applications with more LS launch options. The following API has been added:
- (BOOL)launchAppWithBundleIdentifier:(NSString *)bundleIdentifier
options:(NSWorkspaceLaunchOptions)options
additionalEventParamDescriptor:(NSAppleEventDescriptor *)descriptor
launchIdentifier:(NSNumber **)identifier;
- (BOOL)openURLs:(NSArray *)urls
withAppBundleIdentifier:(NSString *)bundleIdentifier
options:(NSWorkspaceLaunchOptions)options
additionalEventParamDescriptor:(NSAppleEventDescriptor *)descriptor
launchIdentifiers:(NSArray **)identifiers;
The NSWorkspaceLaunchOptions can be found in NSWorkspace.h. In addition, NSWorkspace now has API to get the absolute path from a bundle identifier:
- (NSString *)absolutePathForAppBundleWithIdentifier:(NSString *)bundleIdentifer;
In the NSWorkspaceDidLaunchApplicationNotification, a new constant NSApplicationBundleIdentifier has been added.

NSWorkspace now provides sleep notifications. NSWorkspaceWillSleepNotification and NSWorkspaceDidWakeNotification will be sent before the machine sleeps and after the machine wakes, respectively. An observer of NSWorkspaceWillSleepNotification can delay sleep for up to 30 seconds within the handling of the notification.

We added NSWorkspaceSessionDidBecomeActiveNotification and NSWorkspaceSessionDidResignActiveNotification notifications to NSWorkspace, for applications that need to be aware of session switching (aka "fast user switching"). For example, an application may decide to disable some processing when its user session is switched out, and reenable when that session gets switched back in. Such an application should register for these notifications.

Additionally, if an application is launched in an inactive session and registers for these notifications, NSWorkspace sends the NSWorkspaceSessionDidResignActiveNotification after sending NSApplicationWillFinishLaunching and before sending NSApplicationDidFinishLaunching.



NSProgressIndicator

We have added a new larger sized spinning progress indicator that corresponds to the NSRegularControlSize. The original smaller sized indicator now corresponds to NSSmallControlSize. If your application is linked against anything before Panther, we will always return the smaller size in order to ensure binary compatibility.


NSPasteboard

NSPasteboard has automatically made "NeXT plain ascii pasteboard type" data available when Carbon applications have put 'TEXT' on a pasteboard, despite the fact that use of this type has not been publicly supported since before Mac OS 10.0. NSPasteboard no longer ensures that this type is available on pasteboards. Use NSStringPboardType instead.

In Mac OS 10.2, NSPasteboard began to automatically provide Carbon kScrapFlavorTypeUnicode ('utxt') and kScrapFlavorTypeUnicodeStyle ('ustl') data when NSRTFPboardType items were put on the pasteboard. The 'utxt' that NSPasteboard provided always began with a Unicode byte order mark (BOM), which is valid. Unfortunately, many Carbon applications were not able to properly handle the BOM. Starting with 10.2.3, the 'utxt' that NSPasteboard automatically provides no longer begins with a BOM. However, because providing the BOM is ultimately the right thing to do, we do intend to bring it back in a future release.


NSPrintInfo

In Mac OS 10.2, -[NSPrintInfo setPaperSize:] began silently ignoring any paper size that didn't match any of the paper sizes supported by the current selected printer. This bug was fixed 10.2.3.

In Mac OS 10.2, -[NSPrintInfo setPaperSize:] began silently ignoring any paper size that was the rotated variant of a paper size supported by the current selected printer. This bug was fixed 10.2.3.

The string returned by -[NSPrintInfo paperName] is usually not suitable for presenting to the user. For example, "na-letter" is very often returned when the user has specified "Letter" in an NSPageLayout. Because some applications needs to present paper names to the user, a new method has been added to NSPrintInfo:
- (NSString *)localizedPaperName;

NSDocument

-[NSDocument lastComponentOfFileName] now returns the exact same value that -displayName would. A valid value for a document's "name" property is now always returned to scripts.

Name specifiers are now the default object specifier form for documents, instead of index specifiers. Index specifiers were not appropriate in many situations because the indices of documents in an application are so likely to change during the execution of a script that manipulates documents.

-[NSDocumentController openDocumentWithContentsOfFile:display:] is now invoked with a display: argument of YES instead of NO when a Print Documents Apple event is handled. For documents that present the print panel as a sheet (document-modally) there must be a visible document window to which the sheet can be attached. For documents that present the print panel as a dialog box (application-modally) the document window provides an indication of what will be printed when the user presses the OK button in the print panel.

In previous versions of Cocoa there was no easy public way to control which window of a multiwindow document should be used as the parent window of sheets presented by that document. Because there is a common need for this, a new method has been added to NSDocument:
- (NSWindow *)windowForSheet;
In previous versions of Cocoa the numbering of untitled documents was done in such a way that it was common for unnecessarily large numbers to appear in the display names of untitled documents, e.g. "Untitled 78." NSDocument now names untitled documents in such a way that each new untitled document is given a number that is one larger than the largest number used in any currently open, untitled, document.

In previous versions of Cocoa -[NSDocument writeWithBackupToFile:ofType:saveOperation:] would fail when passed a document path string that contained colons. Because colons in POSIX-style paths are by convention the result of the user typing a slash in the user interface (either that of the app itself or the Finder), this bug would appear to the user as a failure to save documents whose names contained slashes. This has been fixed.



NSWindow

A local autorelease pool will now be installed and released during live resize for applications built on Panther or later. This allows autoreleased objects to be released during live resize, which improves memory usage but also changes the lifetime of some objects. This change is limited to applications built on Panther or later for compatibility reasons.

We have introduced a delay for dragging from the document icon button. If you click and drag on the document icon button without pausing, the window will move. If you click and pause for 1/8 second, the document icon button will become a drag source. The document icon button will be highlighted to indicate when the drag delay has been satisfied. Additionally, the restriction preventing shift-drags from the document icon button has been lifted. The shift modifier is now ignored for document icon button drags.

Functionality of -setMiniWindowImage: has been reenabled for applications linked on Panther or later. Previously, for compatibility reasons, a special default was needed to enable this.

We now have a method to allow a window delegate to specify a custom sheet location. Most customization involves just the vertical offset , but some apps also want to control the horizontal location in the window. Some apps might want to control the width of the start of the sheet effect as well. For example it might make sense to make a sheet appear as if it was originating from a button or other widget. Note that this is typically a property of the parent window, but may also be dependent on the type of sheet being presented.
@interface NSObject(NSWindowDelegate)
- (NSRect)window:(NSWindow *)window willPositionSheet:(NSWindow *)sheet usingRect:(NSRect)rect;
...
@end
This method will be sent to the window's delegate before first animating the sheet, as well as any time window is resized while sheet is attached. The returned NSRect indicates the line at which the top edge of the sheet should be attached to the window, with the origin in window coordinates and the rect.size.width indicating the width of the initial animation. If rect.size.width is wider than the sheet, the sheet will slide out . If the rect.size.width is narrower than the sheet, the sheet will genie out from the given rect. The top of the sheet will be centered within the given rect. Note that rect.size.height will not currently impact that size of the animation, but will be used to determine the center of the rect.

NSWindow now has methods that do size computations in terms of content rather than frame metrics. This allows specification of window content size which is especially useful in windows which may have a toolbar visible.
- (NSRect)frameRectForContentRect:(NSRect)contentRect
- (NSRect)contentRectForFrameRect:(NSRect)frameRect
The following methods are preferred over the frame-based methods, but the frame-based methods will continue to work if the content-based methods are not used:
- (void)setContentMaxSize:(NSSize)aSize
The above method sets the maximum size to which the receiver's contentView frame can be sized to aSize. The maximum size constraint is enforced for resizing by the user as well as for the setFrame... methods other than setFrame:display:. Takes precedence over setMaxSize:.
- (NSSize)contentMaxSize
Returns the maximum size of the receiver's contentView frame.
- (void)setContentMinSize:(NSSize)aSize
Sets the minimum size to which the receiver's contentView frame can be sized to aSize. The minimum size constraint is enforced for resizing by the user as well as for the setFrame... methods other than setFrame:display:. Takes precedence over setMinSize:.
- (NSSize)contentMinSize
Returns the minimum size of the receiver's contentView frame.
- (void)setContentAspectRatio:(NSSize )ratio
Sets the receiver's content size aspect ratio to ratio, constraining the size of its content rectangle to integral multiples of this size when the user resizes it. You can set the NSWindow's size to any ratio programmatically. Takes precedence over -setAspectRatio:.
- (NSSize)contentAspectRatio
Returns the receiver's content size aspect ratio.
- (void)setContentResizeIncrements:(NSSize)increments
Sets the receiver's resize increments to increments, constraining the width and height of the content rectangle to change by integral multiples of increments.width and increments.height when the user resizes it. You can set the NSWindow's size to any width and height programmatically. Takes precedence over -setResizeIncrements:.
- (NSSize)contentResizeIncrements
The above method returns the receiver's content resize increments.

The default time for sheet and window resize animation has been reduced, so the effects will occur more quickly. If you need to customize this animation to be slower (or faster) in a window subclass, you can override -animationResizeTime: and tweak the value obtained from the super.

We fixed -setIgnoresMouseEvents: so that it works more reliably for opaque windows that want to be transparent to mouse events, and also works for transparent windows that want to receive mouse events. In Jaguar, this API only somewhat worked for ignoring events, and did not work at all for receiving mouse events in transparent windows. This fix applies only to applications built on Panther or later.

We no longer ignore NSMiniaturizableWindowMask for nonActivating utility windows. If this styleMask is set on a nonActivating utility window in an application built on Panther or later, that window will get a minimize button. We will continue to prohibit a minimize button on other types of utility windows.

On Jaguar and previous systems, -[NSPanel orderFront:] would behave like -orderFrontRegardless:, meaning that an NSPanel would be brought to the front of its window level whether or not its owning application was active. In Panther, we have removed this distinction for non-modal NSPanels. NSPanel and NSWindow now behave the same in that orderFront: will order the panel or window behind the active window if the active window belongs to another application. For compatibility, this change applies only to applications built on Panther or later.


NSEvent

NSEvent instance methods now check that instance methods are sent to valid event types, for applications built on Panther or later. This is as documented, but has not previously been enforced. A method sent to the wrong event type will cause an exception to be raised.

The delivery rule for NSScrollWheel events has been changed so that NSScrollWheel events are sent to the view under the mouse in a key or utility window. NSScrollWheel events are dropped if the mouse is not over a key or utility window. NSScrollWheel events may still be passed up the responder chain from the receiving view.In 10.2, the window server started setting an additional device-dependent modifier flag in user input events to indicate when event coalescing is disabled. Applications that check for modifierFlags using equality without masking off the device-dependent modifierFlags first can get unexpected behavior due to this change. In order to maintain compatibility for applications built on Jaguar and earlier systems, NSEvent by default strips this device-dependent modifier flag when creating the event from a windowServer event. For applications built on Panther or later systems, this will no longer be the default behavior. In order to override NSEvent's default behavior, an application can specify a value for the user default NSDeviceDependentModifierFlags. If this default is set to NO, the device-dependent modifier flags will be stripped.

NSApplication

We now ignore the user default NSSuppressReopenAppleEvent for applications built on Panther or later. This default was originally added as a workaround for applications that weren't ready to handle the 'rapp' event, but we would not expect any current applications to need this default.

New delegate methods have been added for opening or printing multiple files at once:
@interface NSObject(NSApplicationDelegate)
...
-(void)application:(NSApplication *)app openFiles:(NSArray *)fileList
-(void)application:(NSApplication *)app printFiles:(NSArray *)fileList
...
@end
If the application delegate implements application:openFiles:, this method will be called instead of application:openFile:. Similarly, application:printFiles: will be called instead of application:printFile:.

Note that the delegate may need to present one or more sheets while handling these methods. There may be error conditions as well. It is the delegate's responsibility to notify the user through an error panel or other means if appropriate. The delegate will also be responsible for indicating failure or user cancel to the sender of the AppleEvent which caused one of these methods to be sent. In order to make replying to the AppleEvent easy, we have provided a wrapper in NSApplication:
typedef enum NSApplicationDelegateReply {
NSApplicationDelegateReplySuccess = 0,
NSApplicationDelegateReplyCancel = 1,
NSApplicationDelegateReplyFailure = 2
} NSApplicationDelegateReply;
-(void)replyToOpenOrPrint:(NSApplicationDelegateReply)reply

The delegate must call this method in order to get the kit to manage error reporting in the reply AppleEvent. If this method is called with NSApplicationDelegateReplyCancel , userCanceledErr will be set in the reply AppleEvent. If this method is called with NSApplicationDelegateReplyFailure, errAEEventFailed is set in the reply AppleEvent. The delegate may also call this method to report success, although the current implementation does not do anything in response to this. Delegates that want to manage the Apple Event reply themselves should do so using NSAppleEventManager API, and should not call this method.

In 10.3, if you pass nil to -setApplicationIconImage:, we will now set the dock icon to the default image for the application. Previously this behavior was undefined.

The AppleEvent handler for the 'quit' event will now return userCanceledErr if there is an application modal panel open. -applicationShouldTerminate will not be invoked on the application delegate in this case. One consequence of this change is that an application with a modal panel open will now be reported as canceling logout. On previous versions of the system, such an application would block logout until the modal panel was dismissed.

System Preferences allows users to add applications to the Startup Items list, and to launch those applications hidden. In Panther, and since the WWDC seed, NSApplication now enforces the hidden-on-launch setting by adding windows ordered onscreen during application launch to a hidden list. This includes any non-modal windows ordered onscreen up to and including the time when -applicationDidFinishLaunching: is sent. Windows ordered onscreen after this time will cause the application to get unhidden. In order to maintain binary compatibility with applications that may not expect this behavior, the hidden-on-launch setting is only enforced for applications built on Panther or later. Applications built on earlier systems will probably see the old behavior, where a window shown during launch will temporarily flash onscreen, then get hidden with the app.

A new API -[NSApplication orderFrontCharacterPalette:] is added.

AppKit now adds "Special Characters..." menu item to the "Edit" menu if an item with -orderFrontCharacterPalette: action is not found in the menu. To prevent the behavior, you can set the NSDisabledCharacterPaletteMenuItem preference setting to YES.



NSBox

We no longer archive or unarchive the contentView for an NSBoxSeparator for keyed coding. The contentView has no purpose for an NSBoxSeparator.

In 10.3 we defer sizing the NSBox after unarchiving until it is first drawn. This means that subviews that resize based on the box size can get resized later than they did on Jaguar and previous systems.

10.3 provides a new appearance for NSBox. Box types of NSBoxPrimary and NSBoxSecondary will both draw with an indented look, enhanced but similar in some ways to how NSBoxSecondary boxes drew on Jaguar. If your application needs a simple outline look, you should use an NSBoxType of NSBoxOldStyle and an NSBorderType of NSLineBorder. It is recommended that you use this only for boxes without titles.


Dragging

A local autorelease pool is now installed and released around NSDraggingDestination method invocations, for applications built on Panther or later. This allows autoreleased objects to be released during dragging, which improves memory usage but also changes the lifetime of some objects. This change is limited to applications built on Panther or later for compatibility reasons.

A bug in generating the drag image would result in a flipped image (isFlipped: set) appearing unflipped if the source was cached (i.e. not a bitmap). The image will now appear in the correct orientation. This change will only affect applications compiled in Panther or later.


NSCursor

Applications built on Panther or later can now use cursor images of sizes other than 16x16. The cursor size will be defined by the size of the image passed to -initWithImage:hotSpot: or -initWithImage:foregroundColorHint:backgroundColorHint:hotSpot:. Applications can check for an NSAppKitVersionNumber greater than or equal to NSAppKitVersionNumberWithCursorSizeSupport to determine whether this support is available.

NSCursor now provides new cursors for alias and copy drags, as well as slightly modified cursors for vertical and horizontal resize. We've also added additional public cursors:
+ (NSCursor *)pointingHandCursor;
+ (NSCursor *)closedHandCursor;
+ (NSCursor *)openHandCursor;
+ (NSCursor *)resizeLeftCursor;
+ (NSCursor *)resizeRightCursor;
+ (NSCursor *)resizeLeftRightCursor;
+ (NSCursor *)resizeUpCursor;
+ (NSCursor *)resizeDownCursor;
+ (NSCursor *)resizeUpDownCursor;
+ (NSCursor *)crosshairCursor;
+ (NSCursor *)disappearingItemCursor;

NSGraphics

The following functions have been added to disable and reenable all drawing to the screen by the calling context:
void NSDisableScreenUpdates(void);
Prevents drawing for all windows belonging to the calling process from being flushed to the screen. This function permits operations on multiple windows to appear atomic to the user, and is particularly useful for parent and child windows. Note that this function should be used with care for short operations only as the system will only allow updates to be disabled for a short time (currently one second) before automatically reenabling updates.
void NSEnableScreenUpdates(void);
Reenables drawing for all windows belonging to the calling process. Calls to NSDisableScreenUpdates must be matched with calls to NSEnableScreenUpdates. Multiple calls stack.



NSHelpManager

We now have methods to support help lookup other than from the Help Menu. The following methods support navigation to a specific location in a help book, or querying a help book for a string when a Help button is pressed, for example.
- (void)openHelpAnchor:(NSString *)anchor inBook:(NSString *)book
Find and display the text at the given anchor location in the given book. The argument should be a localized help book name or nil --- if nil, all installed help books are searched. This is a wrapper for AHRegisterHelpBook (which is called only once to register the help book specified in the application's main bundle) and AHLookupAnchor.
- (void)findString:(NSString *)query inBook:(NSString *)book
Search for the given query in the given book. The argument should be a localized help book name or nil --- if nil, all installed help books are searched. This is a wrapper for AHRegisterHelpBook (which is called only once to register the help book specified in the application's main bundle) and AHSearch.


Accessibility

The AXWindows attribute of the application UI Element now returns the list of window in z-order, front-to-back.

AXWindows now support a raise action which simulates bringing a window forward by clicking on its title bar.
NSAccessibilityRaiseAction
AXWindows now support subroles to distinguish different types of windows.
NSAccessibilityStandardWindowSubrole
NSAccessibilityDialogSubrole
NSAccessibilitySystemDialogSubrole
NSAccessibilityUnknownSubrole
NSAccessibilityFloatingWindowSubrole
NSAccessibilitySystemFloatingWindowSubrole
AXWindow's title attribute used to include the path name for windows with represented files (as per [NSWindow title]). This has now been fixed so they only return the displayed title. You should access the represented file with the AXDocument attribute.

AXWindows now support attributes to identify their default and cancel buttons.
NSAccessibilityDefaultButtonAttribute
NSAccessibilityCancelButtonAttribute
Windows now emit notifications when AXDrawers and AXSheets are created.
NSAccessibilityDrawerCreatedNotification
NSAccessibilitySheetCreatedNotification
AXScrollBars now expose their arrows and page up/down areas as AXButtons with subroles.
NSAccessibilityIncrementArrowSubrole
NSAccessibilityDecrementArrowSubrole
NSAccessibilityIncrementPageSubrole
NSAccessibilityDecrementPageSubrole

10.3 provides more powerful text accessibility features. A number of new attributes were added for AXTextAreas and AXTextFields in order to return more detailed information about the text within. These additions are documented in the Accessibility APIs.


Two new methods were added to the Cocoa accessibility protocol in order to support parameterized attributes – one to return a list of them and one to return their values.
- (NSArray *)accessibilityParameterizedAttributeNames;
- (id)accessibilityAttributeValue:(NSString *)attribute forParameter:(id)parameter;
A new function was added so you can raise an error if the parameter is the wrong type or has an illegal value. This function can also be used to raise an error if an attempt is made to set an attribute's value with the wrong type or an illegal value.
void NSAccessibilityRaiseBadArgumentException(id element, NSString *attribute, id value);
The following constants have been removed:
NSAccessibilityWindowTitleRole
NSAccessibilityWindowProxyRole
NSAccessibilityRelevanceIndicatorRole
The following constants have been added:
NSAccessibilityCancelAction


NSSound

NSSound uses CoreAudio to play most files in 10.3, but uses QuickTime to play some sound formats, like iTunes Music Store sounds and general URLs. In 10.2, NSSound primarily used QuickTime to play sounds.

Unfortunately, the underlying requirements and limitations of the underlying frameworks bleed through to NSSound, and affect developers trying to use NSSound to play sounds on multiple threads. If your app is single-threaded, or you only play sounds on the main thread, then you need not worry about these issues.

Since QuickTime requires the run loop to be run for sound (or movies) to continue playing, NSSound requires this as well. By "run loop", what is meant is the run loop on the thread which starts the sound playing. For Cocoa applications, this is not a big deal for sounds played on the main thread, as Cocoa apps normally let the AppKit handle running the run loop on the main thread. Also, since QuickTime is not particularly thread-safe, it is not recommended to play sounds (or movies) on multiple threads.

The delegate -sound:didFinishPlaying: is also sent on the main thread, when it is automatically triggered by the sound finishing. However, when -stop is called it is sent immediately on that thread calling -stop. So unless one does all sound playing and stopping on the main thread, one cannot assume that the delegate method is being called on the main thread.

Doing all sound playing on the main thread will also insulate you better from future changes in the multi-threaded behavior of NSSound and the underlying frameworks.


Playing an NSSound more than once simultaneously

A given NSSound instance can only be playing, or not. If a sound is playing, and -play is called, nothing will happen. This was true in 10.2, and is still true in 10.3, and will be true in the future. However, a different NSSound instance can play the same sound file. So if you want the same sound potentially played overlapping, make a copy of the NSSound and play the copy:
[[[mySound copy] autorelease] play];

NSBrowser

NSBrowser scrolling now provides immediate and continuous feedback. This of course provides a much better user experience, but also required some major changes. In particular, the internal view hierarchy had to change. So, if you have subclasses of NSBrowser or NSBrowserCell which depend on the internal view hierarchy, you should be on the look out for incompatibilities. In Panther, continuous scrolling is on by default for all applications. However, if necessary, you can revert to the old implementation by setting the NSBrowserSupportsContinuousScrolling default to NO. The old, non-continuous scrolling implementation remains for compatibility and will be removed in the next release.

The implementation of continuous scrolling has the following implications:

The internal view hierarchy has changed. However, the public API dealing in browser geometry still returns values in browser coordinates. For example, -titleFrameOfColumn:, and -frameOfColumn: return rectangles relative to the NSBrowser.

Overriding NSBrowser's -drawRect: method is no longer very useful (due to the new view hierarchy).

The -drawTitleOfColumn:inRect: method's 'inRect' parameter is in the coordinates of the view that draws the titles. You do not need to do any conversion in order to draw.

The size of a browser's columns may now vary by one pixel. This happens when the available space for column tilling cannot be evenly divided by the number of visible columns.

The usage of the delegate methods -browserWillScroll: and -browserDidScroll: require some explanation. The non-continuous implementation sent these delegate messages each time a new column became visible. However, with continuous scrolling, partial columns can now be visible during scrolling. The continuous scrolling implementation uses these methods before and after scrolling has completed. So, these methods are no longer visibility notifications.

The use of -scrollViaScroller: is deprecated. This method no longer does anything when using the continuous scrolling implementation

The use of -updateScroller is deprecated. This method no longer does anything when using the continuous scrolling implementation.

Note, one can check for the support of the continuous scrolling by comparing the appkit version number against NSAppKitVersionNumberWithContinuousScrollingBrowser.


NSBrowser now provides three different column resizing modes: NSBrowserNoColumnResizing, NSBrowserAutoColumnResizing, and NSBrowserUserColumnResizing. For many applications auto resizing will be sufficient. In auto resizing, each column is given the same width, which is calculated using a combinination of the minimum column width, and max visible columns setting. Some applicaitons may decide that they know how to size columns better than NSBrowser, or the user, and will choose to use no column resizing. In NSBrowserNoColumnResizing mode, the developer explicitly will determine the width of every column, and neither the user, nor NSBrowser will change the assigned width. Finally, NSBrowser allows a column resizing mode that allows developers to choose the initial column width, while allowing users the option to resize the columns much like they can in the Finder.

NSBrowsers user column resizing mode (NSBrowserUserColumnResizing), and no column resizing mode (NSBrowserNoColumnResizing) deserve a little further explanation since they are new. Essentially auto column resizing is the same as the old browser behavior. A number of new methods and delegate methods have been introduced to support the two new modes. First of all, there is new API to specify the type of column resizing:
typedef enum _NSBrowserColumnResizingType {
NSBrowserNoColumnResizing = 0, /* Column sizes are fixed and set by developer. */
NSBrowserAutoColumnResizing = 1, /* No user resizing. Columns grow as window grows. */
NSBrowserUserColumnResizing = 2 /* Columns fixed as window grows. User can resize. */
} NSBrowserColumnResizingType;
- (void)setColumnResizingType:(NSBrowserColumnResizingType)columnResizingType;
- (NSBrowserColumnResizingType)columnResizingType;
- (void)setPrefersAllColumnUserResizing:(BOOL)prefersAllColumnResizing;
- (BOOL)prefersAllColumnUserResizing;
Next, there is new API and delegate methods that allow you to declare the initial size for a newly visited browser column. There is also API that allows you to directly set the width of a column:
- (void)setWidth:(float)columnWidth ofColumn:(int)columnIndex;
- (float)widthOfColumn:(int)column;
@interface NSObject (NSBrowserDelegate)
- (float)browser:(NSBrowser *)browser
shouldSizeColumn:(int)columnIndex
forUserResize:(BOOL)forUserResize
toWidth:(float)suggestedWidth;
- (float)browser:(NSBrowser *)browser
sizeToFitWidthOfColumn:(int)columnIndex;
@end
Finally, there is new API to do simple column width persistence, and new notifications that allow you to do more sophisticated path based column width persistence:
- (void)setColumnsAutosaveName:(NSString *)name;
- (NSString *)columnsAutosaveName;
+ (void)removeSavedColumnsWithAutosaveName:(NSString *)name;
APPKIT_EXTERN NSString * NSBrowserColumnConfigurationDidChangeNotification AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER;
// Object : browser - the browser whose column sizes need to be persisted.
// UserInfo : No user info.
@interface NSObject (NSBrowserDelegate)
- (void)browserColumnConfigurationDidChange:(NSNotification *)notification;
@end

NSBrowser no longer loses focus during a reloadColumn:, or loadColumnZero.

Performing a selectAll: on a matrix in a browser now works. In the past, only "loaded" cells would be part of the selection when finished. This has been fixed. So, as part of a select all, cells are loaded if necessary.

NSBrowsers double and single click action are not sent until the browsers sliding animation has completed.

The existing -maxVisibleColumn/setMaxVisibleColumns: are ignored and not applicable for browser using NSBrowserNoColumnResizing, or NSBrowserUserColumnResizing types.

The use of -displayColumn: is deprecated. Use setNeedsDisplayInRect: with the appropriate rectangle instead.

The use of displayAllColumns is deprecated. Use setNeedsDisplay, or setNeedsDisplayInRect: with an appropriate rectangle instead.




NSBrowserCell

Leaf browser cells now draw their contents all the way to the end of their row's visible area. In Jaguar and prior releases, the contents stopped where the branch indicator would have been if the cell was not a leaf.

For applications linked on or after Panther, NSBrowserCell's -cellSize calculation will now include the width required for its image and arrow if necessary. Applications linked on earlier systems will still have the old buggy behavior. The old behavior returned a value that was too small because the image, arrow, and a spacing were not figured into the desired cell size.


NSComboBox

NSComboBox cell no longer allows users to click its button when disabled.

NSComboBox can now be displayed without the "border" around its button. It is often useful in NSTableView for instance to not display the button border. To configure this setting, use the new API:
- (void)setButtonBordered:(BOOL)flag;
- (BOOL)isButtonBordered;

NSOutlineVIew

NSOutlineView's disclosure triangle now animates.

-(void)collapseItem:(id)item collapseChildren:(BOOL)flag now actually will collapse children if asked to do so
-(id)outlineView:(NSOutlineView *)olv itemForPersistentObject:(id)object no longer raises an exception if a nil value is returned.

Sorting UI - see NSTableView's "Sorting UI" information.



NSTabView

For applications linked against Panther and later, -tabViewItems now returns an immutable array. It has always been declared to return an immutable array, but until now has always returned a mutable array.

When an NSTabViewItem is removed from a tab view, its state will now always be set to NSBackgroundTab.


NSTableView

NSTableView now implements the NSUserInterfaceValidations protocol, and specifically validates the selectAll: target/action method.

NSTableView and NSOutlineView draw a keyboard focus indication if there is enough room to display one. The focus indication is drawn either around the enclosing scroll view, or around the table and header (when not enclosed in a scroll view). If there is not enough room to display most of the focus ring, then none is shown.

In Jaguar and prior releases, -selectedCell would only returned a non-nil value when editing text via a double click. Now, in apps linked against Panther or later, selectedCell always returns the cell that was clicked, regardless of what type of cell was clicked. So, while the user clicks on a NSSliderCell and drags the mouse around, the table will return the slider cell that is being manipulated from -selectedCell. This will allow you to query the current slider value from your action method.

For applications linked against Panther or later, NSTableView now returns YES from -needsPanelToBecomeKey. This means that users can navigate to a table using the <tab> key. Previously, unless you subclassed NSTableView and overrode this method, the user would have to be in "Any Controls" keyboard navigation mode to be able to <tab> to a table. If the table is in a panel that returnes YES from becomesKeyOnlyIfNeeded, then this needsPanelToBecomeKey to become key returns YES only if the panel is currently key. By doing this, clicks in such panels will not force the panel to become key. Note that double clicking in a text cell to start editing will force the panel to become key.

NSTableHeaderView now waits until mouse up to select or deselect a column. If the user has clicked in an previously unselected header, the header will be drawn in a pressed (NSOnState) but not selected state until the user mouses up in the header cell. Among other things, this means that a column doesn't have to be selected in order to be moved by a user.

NSTableView supports autohiding its scrollers. However, using a customized corner view with autohiding scrollers on is currently not recommended because the corner view will disappear at the same time the vertical scroller disappears .

NSTableHeaderCell has fixed a bug with the positioning of its indicator image. Prior to Panther, indicator images set using NSTableView's -setIndicatorImage:inTableColumn: resulted in an image that was drawn too low, such that only the top half of the image was visible. NSTableHeaderCell now properly centers the image. The image was also allowed to be too close to the header text. This was fixed by decreasing the width available to the header text. Both fixes apply to applications linked on Panther and later only.

NSTableView's last table column now draws its column highlight all the way to the end. All other columns leave a small gap between column highlights (if there is an inter-cell spacing) by ending their column highlight short of the actual end of the column.

NSTableView now caches the results from numberOfRowsInTableView: when possible. In the past, NSTableView messaged the data source for this value an inordinate amount of times .


NSTableView now supports drawing its background using the standard alternating colors used by many applications, such as iTunes. The new flags are saved in old and new style keyed archiver. This feature can be adopted at IB design time, or at runtime using the following new API:
- (void)setUsesAlternatingRowBackgroundColors:(BOOL)useAlternatingRowColors;
- (BOOL)usesAlternatingRowBackgroundColors;
NSTableView now exposes an override point to allow complete background coloring customization. To customize background drawing, override the following new API:
- (void)drawBackgroundInClipRect:(NSRect)clipRect;

NSTableView now provides index set based selection API, using the new NSIndexSet class:
- (void)selectColumnIndexes:(NSIndexSet *)indexes byExtendingSelection:(BOOL)extend;
- (void)selectRowIndexes:(NSIndexSet *)indexes byExtendingSelection:(BOOL)extend;
- (NSIndexSet *)selectedColumnIndexes;
- (NSIndexSet *)selectedRowIndexes;

The following non-index set based APIs have been deprecated:
- (void)selectColumn:(int)column byExtendingSelection:(BOOL)extend;
- (void)selectRow:(int)row byExtendingSelection:(BOOL)extend;
- (NSEnumerator *)selectedColumnEnumerator;
- (NSEnumerator *)selectedRowEnumerator;

NSTableView now provides a general sorting API on NSTableView which will make sorting UI implementation easier. The API consists of methods that will allow NSTableView to automatically manage the sorting UI and to create sort descriptors to be used by the data source when the user clicks on a table header. The data will not be automatically sorted, but the data source will be told when it should resort its data.

A table column is considered sortable if it it has a sortDescriptorPrototype. A sort descriptor contains three pieces of information: a key, selector, and sort direction. When used as a column prototype, the sort descriptor defines several interesting things. First, the presence of a sort descriptor prototype indicates the column is sortable. Next the prototype's sort direction defines the initial sorting direction. Finally, the key and selector definition provide a convenient location to store information the data source will need when sorting. Note that it is not required that the key match the table columns identifier, however the key must be unique from the key used by other columns.
// NSTableColumn.h
- (void)setSortDescriptorPrototype:(NSSortDescriptor *)sortDescriptor;
- (NSSortDescriptor *)sortDescriptorPrototype;
Given a table with sortable columns, NSTableView will automatically manage the sorting UI. NSTableView automatically displays a sort indicator for the primary sort column. To accomplish this, NSTableView maintains a list of sort descriptors. The first sort descriptor in the list defines the primary sort key, selector, and direction. The array of sort descriptors is archived. Also, the array of sort descriptors will persist along with other column information if an autosave name is set.
// NSTableView.h
- (void)setSortDescriptors:(NSArray *)array;
- (NSArray *)sortDescriptors;
@end
Now, since NSTableView doesn't manage the data, it can't sort if for you. However, it does tell you when the data needs to be re-sorted.
@interface NSObject (NSTableDataSource)
- (void)tableView:(NSTableView *)tableView sortDescriptorsDidChange:(NSArray *)oldDescriptors;
@end
@interface NSObject (NSOutlineDataSource)
- (void)outlineView:(NSOutlineView *)outlineView sortDescriptorsDidChange:(NSArray *)oldDescriptors;
@end
NSTableHeaderCell provides override points for customizing the sorting UI look. -drawSortIndicatorWithFrame:inView:ascending:priority: is called for each column that participates in sorting. However, by default NSTableHeaderCell only draws an indicator if priority is 0, that is, if the column is the primary sort column.
@interface NSTableHeaderCell
- (void)drawSortIndicatorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView ascending:(BOOL)ascending priority:(int)priority;
- (NSRect)sortIndicatorRectForBounds:(NSRect)theRect;
@end

NSTableView grid drawing now works properly. However, many nibs have been unknowingly saved with the "draws grid" flag checked in IB. To avoid having recompiled apps accidentally showing grids, the old flag is completely ignored. This is not a big deal since the flag was never used anyway. Proper archiving of the grid drawing flag are only supported by the keyed archiver.

NSTableView now respects the alpha in grid colors.

NSTableView now allows much finer grid drawing control. In addition to drawing a full grid, you may now choose to draw vertical or horizontal grid lines only using the -setGridStyleMask:(unsigned int)gridStyleMask API. Only nibs saved with the keyed archiver will save this information. Note that, with the addition of this API, the old grid drawing API becomes redundant, and has therefore been deprecated.

These methods have been deprecated:
- (void)setDrawsGrid:(BOOL)drawGrid;
- (BOOL)drawsGrid;

NSTableColumn

Although NSTableColumn has conformed to NSCoding for a long time, it now finally declares this conformance in its header.


NSToolbar

Toolbar items which have an NSBox as their view used to force the box to use NSNoBorder in the toolbar, and NSLineBorder in the customization palette. NSToolbarItem no longer does this.


NSToolbar now supports displaying the selected toolbar item in toolbars that are used as mode switchers (e.g. inspectors, color panel, etc...). The toolbar delegate must implement -toolbarSelectableItemIdentifiers to indicate which type of toolbar items can be used to indicate mode. Note that, since toolbars are very dynamic in their content, item selection is maintained by "item identifier", not by item. NSToolbar maintains selection automatically for image type items. However the selected item identifier can be explicitly set to anything by calling -setSelectedItemIdentifier:.


"Poof" Animation

A new function, NSShowAnimationEffect() has been added to allow developers to use the same item removal animation used by controls such as toolbar and the dock. Although the API is designed as a general mechanism for system animation effects, currently only one animation exists. To run an animation, you specify the type of animation you want, the size and location of the animation, and optional callback information. The NSAnimationEffectDisappearingItemDefault effect is meant to indicate removal from a list, without actually destroying the underlying item. For example, removal from the dock does not delete the file. The NSAnimationEffectPoof simply shows a disappearing cloud, poof effect. Currently NSAnimationEffectDisappearingItemDefault and NSAnimationEffectPoof are the same effect, but they are not guaranteed to be the same in the future.


ToolTips

Tooltips that are too large now automatically wrap. This can be disabled by setting the default NSToolTipAutoWrappingDisabled to YES.

Prior to Panther, if a user activated a window by clicking in an area with tooltips no tooltips would be displayed until the user moved the mouse out of the tooltip area and then back in that area. This bug has been fixed.


Prior to Mac OS X 10.3, tooltips only displayed in the key window of the active application. In Mac OS X 10.3, tooltips now always display in the active application. However, for performance reasons tooltips are not active if your application is inactive (or in the background). This is for performance reasons. If tooltips are enabled, moving the mouse over a background app's window will cause the app to do work, which may degrade the system performance. To allow your application to use tooltips even when it is the background application, use the following new API:


@interface NSWindow (NSToolTip)
- (void)setAllowsToolTipsWhenApplicationIsInactive:(BOOL)allowWhenInactive;
- (BOOL)allowsToolTipsWhenApplicationIsInactive;
@end

NSBezierPath

The bug causing -appendBezierPathWithGlyphs:count:inFont: and -appendBezierPathWithPackedGlyphs: mehods not to advance after each glyph was fixed. Also, -appendBezierPathWithGlyphs:count:inFont: no longer modifies the current graphics context (it doesn't call -[NSFont set]). This means it is the caller's responsibility to use fonts with matrix to flip when the target view is flipped.

Finally, these methods now move the current point to the last glyph's baseline position. In other words, successive calls to these methods correctly aligns glyphs on the baseline.



NSGraphicsContext

+saveGraphicsState and -saveGraphicsState no longer save the current path.


NSFormatter

The NSFormatter's partial validation methods are now correctly invoked at the end of a marked text session. If the formatter returns NO in this situation and consequently -[NSTextView shouldChangeTextInRange:replacementString:] returns NO, the field editor still removes the range of text in the current marked session.



Text Document Reading/Writing

A method has been added to NSMutableAttributedString:
- (BOOL)readFromData:(NSData *)data
options:(NSDictionary *)options
documentAttributes:(NSDictionary **)dict;
which parallels the existing readFromURL:options:documentAttributes:, but operates on the contents of the file as data rather than requiring a file to exist. The readFromURL:options:documentAttributes: method is usually preferable if a file already does exist, since it can make use of filesystem attributes such as extension and type to help determine the type of the file, but the new method is more convenient if a file does not already exist, or if for some reason one does not wish filesystem attributes to be taken into consideration. In Java, the constructor for NSAttributedString and NSMutableAttributedString that takes two arguments, an NSData and an NSMutableDictionary, will now use this method to construct an attributed string from data of any format the text system can read.

A new text document type is now supported,
NSString *NSDocFormatTextDocumentType;
corresponding to Microsoft Word documents. These documents may be read using any of the existing NSAttributedString/NSMutableAttributedString methods for reading text documents. They may be also be read and written using the new NSAttributedString methods
- (id)initWithDocFormat:(NSData *)data documentAttributes:(NSDictionary **)dict;
- (NSData *)docFormatFromRange:(NSRange)range documentAttributes:(NSDictionary *)dict;
Currently the two most recent major revisions of the format are supported for reading (corresponding roughly to Word 6 and later), but only the most recent major revision is supported for writing. Note that this does not imply support for all of the features expressible in such a document, any more than the existing RTF reading implies support for all features potentially expressible in RTF. In fact, Cocoa's feature support for doc format reading and writing is very nearly equivalent to its support for RTF reading and writing. This support has, however, been enhanced to include the features described in the sections on additional text attributes and additional paragraph style features.

The "Converted" key in the document properties dictionary has been reinterpreted, in a way that is consistent with its previous definition. Previously positive values specified that the document had been converted to the format specified by a filter service, and all other values specified that the file was originally in the format specified. That is still the case, but now there is a distinction between negative values and 0 (or not present). Now negative values imply that the file was originally in the format specified, but that the conversion from the format specified to NSAttributedString may have been lossy. In addition there are two new document property keys: "DefaultTabInterval", which specifies the document-wide default tab interval for the document. and "BackgroundColor", which specifies the document-wide background color for pages.


There is a new NSAttributedString HTML import method,
- (id)initWithHTML:(NSData *)data options:(NSDictionary *)options documentAttributes:(NSDictionary **)dict;
that takes an options dictionary like those used by other similar AppKit text import methods. In addition to the relevant existing options keys (BaseURL and CharacterEncoding) there are some new options keys intended specifically for HTML import, that may be used with this method and with the other methods that take an options dictionary:

@"UseWebKit" (NSNumber containing int; if present and positive, forces WebKit-based HTML importing be used; behavior if this is turned on may differ from that of HTML import in Mac OS X 10.2 and before, particularly for tables)
@"TextEncodingName" (NSString containing the name, IANA or otherwise, of a text encoding to be used if the encoding cannot be determined from the document; mutually exclusive with CharacterEncoding)
@"Timeout" (NSNumber containing float; time in seconds to wait for a document to finish loading; if not present or not positive, a default timeout will be used)
@"WebPreferences" (WebPreferences; if WebKit-based HTML importing is used, specifies a WebPreferences object; if not present, a default set of preferences will be used)
@"WebResourceLoadDelegate" (NSObject; if WebKit-based HTML importing is used, specifies an object to serve as the WebResourceLoadDelegate; if not present, a default delegate will be used that will permit the loading of subsidiary resources but will not respond to authentication challenges)


Images in SimpleText files are now centered, like they were in SimpleText. Also, images in Japanese SimpleText files are now displayed.

Methods to load files in NSAttributedString will now try to recognize XML files and use the character encoding specific in the header of the XML if they can. This is just a heuristic, not always applicable; it will not be used if the caller provides an explicit encoding.

Links (as represented by NSLinkAttributeName and stored as NSString, or more preferably as NSURL) in text are now read from and written to RTF files. The format used is compatible with one used by Word.



Text Attributes

The following attributes have been added to the text system:
NSString *NSStrokeWidthAttributeName; /* float, in % of font size, default 0: no stroke; pos for stroke alone; neg for stroke+fill */
NSString *NSStrokeColorAttributeName; /* NSColor, default nil: same as foreground color */
NSString *NSShadowAttributeName; /* NSShadow, default nil: no shadow */
NSString *NSObliquenessAttributeName; /* float; shear to be applied to glyphs, default 0 (no shear) */
NSString *NSExpansionAttributeName; /* float; log of expansion factor to be applied to glyphs, default 0 (no expansion) */
NSString *NSCursorAttributeName; /* NSCursor, default IBeamCursor */
NSString *NSToolTipAttributeName; /* NSString, default nil: no tooltip */
NSString *NSUnderlineColorAttributeName; /* NSColor, default nil: same as foreground color */
NSString *NSStrikethroughStyleAttributeName; /* int, default 0: no strikethrough */
NSString *NSStrikethroughColorAttributeName; /* NSColor, default nil: same as foreground color */
Quartz allows text to be drawn as outlines (stroke) or solids (fill), or both, potentially in different colors. Previously Cocoa text drawing has always used fill drawing. The new stroke width and stroke color attributes allow stroke drawing as well. The actual stroke width used is the absolute value of the attribute; stroke drawing alone is indicated by a positive value, stroke and fill by a negative value, and fill alone by a zero value or the lack of the attribute. The value is given as a percentage of font point size so that a single value can have a consistent meaning across multiple fonts. The foreground color continues to be used as the fill color. If a separate stroke color is specified, it will be used as the stroke color; otherwise the foreground color is used for both stroke and fill.

The previous values for NSUnderlineStyle, NSNoUnderlineStyle = 0 or NSSingleUnderlineStyle = 1, or'ed with NSUnderlineByWordMask for underlining by word and/or NSUnderlineStrikethroughMask for strikethroughs, are now deprecated (except for NSUnderlineByWordMask), although they are still defined and supported for compatibility. The new values for NSUnderlineStyle are
enum {
NSUnderlineStyleNone = 0x00,
NSUnderlineStyleSingle = 0x01,
NSUnderlineStyleThick = 0x02,
NSUnderlineStyleDouble = 0x09
};
or'ed with one of the following:
enum {
NSUnderlinePatternSolid = 0x0000,
NSUnderlinePatternDot = 0x0100,
NSUnderlinePatternDash = 0x0200,
NSUnderlinePatternDashDot = 0x0300,
NSUnderlinePatternDashDotDot = 0x0400
};
and with NSUnderlineByWordMask if underlining is to be by word. The color of the underline is specified by NSUnderlineColorAttributeName; if no color is specified, the foreground color is used.

Instead of an NSUnderlineStrikethroughMask in the underline style, there is now a separate NSStrikethroughStyleAttributeName attribute, with the same set of values as NSUnderlineStyleAttributeName. There is also an NSStrikethroughColorAttributeName to control the strikethrough color; if no color is specified, the foreground color is used. Correspondingly, there are now two additional NSLayoutManager methods to draw the strikethroughs, parallel to the two existing underline methods:
- (void)drawStrikethroughForGlyphRange:(NSRange)glyphRange
strikethroughType:(int)underlineVal
baselineOffset:(float)baselineOffset
lineFragmentRect:(NSRect)lineRect
lineFragmentGlyphRange:(NSRange)lineGlyphRange
containerOrigin:(NSPoint)containerOrigin;
- (void)strikethroughGlyphRange:(NSRange)glyphRange
strikethroughType:(int)underlineVal
lineFragmentRect:(NSRect)lineRect
lineFragmentGlyphRange:(NSRange)lineGlyphRange
containerOrigin:(NSPoint)containerOrigin;
There are three one-parameter subgroups of the affine group that are clearly useful as transformations of text laid out on baselines such as the Cocoa text system provides. Dilatation has always been available in the form of the font's point size. The two remaining subgroups are (a) a one-dimensional dilatation, corresponding to compression or expansion of the text along the x-axis; and (b) a shear transformation, specifically the one that leaves the baseline of the text unaltered, but makes the remainder of the text either more or less oblique. These are expressed by the attributes NSExpansionAttributeName and NSObliquenessAttributeName respectively. The values are chosen so that both appear as additive groups, in particular so that 0 represents the identity.

The new NSCursorAttributeName and NSToolTipAttributeName attributes support the ability to change the cursor and display tooltips over portions of text in a text view. Like NSLinkAttributeName, these attributes usually will be set programmatically rather than by user action. In addition, NSTextView now has a delegate method,
- (NSString *)textView:(NSTextView *)textView
willDisplayToolTip:(NSString *)tooltip
forCharacterAtIndex:(unsigned)charIndex;
which will be called if NSToolTipAttributeName attribute is actually set on the characters over which the mouse is hovering, and which allows the delegate to modify (by returning a different string) or suppress (by returning nil) the display of the tooltip at the time of display.

Note that cursors and tooltips are active only if the text view is selectable. Non-selectable text views do not process any mouse events. If for some reason it is necessary to disallow user selection change in a text view that handles mouse events, this can be achieved by making the text view selectable but implementing the delegate method textView:willChangeSelectionFromCharacterRange:toCharacterRange: to disallow selection changes.


Temporary and Link Text Attributes

Some text attributes affect glyph generation and/or layout, and some do not. The latter include color attributes of all types, underlines and strikethroughs, cursors, and tooltips. Only the latter are candidates for temporary attributes on the layout manager, or for selected or marked text attribute on the text view. Other attributes will be ignored if they are used as temporary, selected, or marked text attributes. In addition, there is a new set of attributes on the text view, the link text attributes. These will be applied--that is, to be added, overriding only existing values of the same attributes--to link text when drawing to the screen, just as the selected and marked text attributes are applied to selected and marked text. The following methods have been added to NSTextView:
- (void)setLinkTextAttributes:(NSDictionary *)attributeDictionary;
- (NSDictionary *)linkTextAttributes;
For pre-Panther applications the default value is an empty dictionary, while for Panther-linked applications the default is blue text with an underline, and an appropriate cursor. Note that linkTextAttributes is intended for those who wish all links to acquire certain attributes; applications wishing to decorate different links differently can use temporary attributes for this purpose, which will take precedence over the corresponding link text attributes.


Additional Text UI

The text ruler accessory has changed significantly, and several additional panels have been added to give users additional control over character and paragraph attributes. In support of this, a method has been added to NSTextView:
- (void)changeAttributes:(id)sender;
somewhat parallel to the existing changeFont:. When changeAttributes: is called, it invokes a new method
- (NSDictionary *)convertAttributes:(NSDictionary *)attributes;
on the sender of changeAttributes:, successively with each set of attributes used in the current selected range (or in the typing attributes). The sender then makes whatever attribute changes it desires and return a converted dictionary. The sender is expected to leave untouched attributes it is not interested in. This can also be used for custom controls that might be supplied for various text attributes. In addition, NSTextView now provides a notification and corresponding delegate method when typing attributes change, whether or not text has changed as a result--for example, when "Bold" is selected but there is a zero-length selection. This can be used to keep track of all changes to text attributes:
NSString *NSTextViewDidChangeTypingAttributesNotification;
- (void)textViewDidChangeTypingAttributes:(NSNotification *)notification;
There are also two new methods on NSFontManager:
- (void)orderFrontStylesPanel:(id)sender;
- (void)setSelectedAttributes:(NSDictionary *)attributes isMultiple:(BOOL)flag;
The latter is used by NSTextView to notify the new panels when attributes change. The former is an action method the main panel to be displayed, intended for use with menu items.


NSTextStorage

NSTextStorage was failing to unregister its delegate for notifications while being deallocated. It now sets its delegate to nil in dealloc, which deregisters the delegate as observer.


NSTextView

Several miscellaneous additional methods have also been added to NSTextView. To support an "Outline" font menu item, an action method has been added:
- (void)outline:(id)sender;
Like underline:, it will add the relevant attribute if absent, or remove it if not. Also like underline:, it uses a default value for the relevant attribute--in this case, the attribute is NSStrokeWidthAttributeName, and the default value is 3.0.

To support changing the base directionality of a paragraph--for example, for Hebrew or Arabic--an action method has been added:
- (void)toggleBaseWritingDirection:(id)sender;
An additional action method has been added
- (void)changeDocumentBackgroundColor:(id)sender;
to support user changes of the background color of the text view (and all of its sibling text views). The term "document" is added to the name to distinguish this background color from the text background color, as specified by NSBackgroundColorAttributeName, which applies only to particular ranges of text and not to the document as a whole. This background color is the view's backgroundColor, and it is the background color that would be expected to be used in connection with the "BackgroundColor" document property described above. Since not all text views will wish to allow users to change the document background color, there is a flag (default value NO) that determines whether this is allowed, and methods to set and get its value:
- (void)setAllowsDocumentBackgroundColorChange:(BOOL)flag;
- (BOOL)allowsDocumentBackgroundColorChange;
A new drawing method has been added,
- (void)drawViewBackgroundInRect:(NSRect)rect;
which is called when the text view intends to draw its background, and which subclasses can override to perform additional drawing behind the text of an NSTextView.

An NSTextView now has a default paragraph style, which clients may set, and which it will use when no paragraph style is explicitly specified, and which the user will be able to revert to using the ruler. If no client sets this, then [NSParagraphStyle defaultParagraphStyle] will be used.
- (NSParagraphStyle *)defaultParagraphStyle;
- (void)setDefaultParagraphStyle:(NSParagraphStyle *)paragraphStyle;
In combination with the new defaultTabStop property of the NSParagraphStyle, this provides a simple way of providing default tab stops throughout a document--for example, in a plain text document.


We now have a standard find panel, usable by NSTextView. The following two methods in NSTextView allow enabling/disabling the standard find panel:
- (void)setUsesFindPanel:(BOOL)flag;
- (BOOL)usesFindPanel;
By default newly created NSTextViews in IB have this attribute set, but for compatibility reasons programmatically created or already archived instances do not.

The following method is the generic action method for the find panel and find menu:
- (void)performFindPanelAction:(id)sender;
This is added to NSTextView, and can be overridden by views which want to provide their own find panel. The actual operation is determined by the tag values such as NSFindPanelActionNext, etc; see the enum NSFindPanelAction.

In 10.3 the find panel is meant for NSTextView use only, as there are no methods to provide the degree of reusability that would be needed for other clients to hook up to it.

When loading custom user-specific key binding dictionaries from ~/Library/KeyBindings, the text system no longer looks for a DefaultKeyBinding.plist file, just DefaultKeyBinding.dict. The former is not mentioned in the documentation, but some older user setups might have that file instead of the preferred DefaultKeyBinding.dict.


Text Completion

NSTextView now has a default implementation of the first responder method complete:, which is bound by default to option-Escape and also F5. The intent of complete: is to provide users with a choice of completions for the word currently being typed. By default the text system will not invoke complete: automatically, but rather only if the user presses a key to which it is bound; however, clients of the text system may obtain autocompletion by invoking complete: programmatically when desired. NSTextView will supply a default list of completions taken from a variety of sources, but clients may replace or modify this list via subclass or delegate methods.

The NSTextView implementation of
- (void)complete:(id)sender;
will in turn call the NSTextView methods (overridable by subclasses)
- (NSRange)rangeForUserCompletion;
- (NSArray *)completionsForPartialWordRange:(NSRange)charRange indexOfSelectedItem:(int *)index;
to get the range of the partial word to be completed, the list of potential completions, and optionally the index in that list of the item to be initially selected. This last method will in turn call the NSTextView delegate method (if implemented)
- (NSArray *)textView:(NSTextView *)text
completions:(NSArray *)words
forPartialWordRange:(NSRange)charRange
indexOfSelectedItem:(int *)index;
which will allow the delegate to modify, override, or suppress the list of completions. For text fields and other controls, we will define an NSControl delegate method
- (NSArray *)control:(NSControl *)control
textView:(NSTextView *)
completions:(NSArray *)words
forPartialWordRange:(NSRange)charRange
indexOfSelectedItem:(int *)index;
to allow the control's delegate the same freedom to control the list of completions used by the field editor. The actual means of presentation of the potential completions will be determined by the NSTextView complete: method; those who wish to modify it will need to override complete:.

The array used in all of these cases is an array of strings, in the order in which they should be presented, representing complete words that the user might be trying to type when starting by typing the partial word at the given range. The results are complete words rather than just the remainder of the word, in case completion requires some slight modification of what the user has already typed--for example, the addition of an accent, or a change in capitalization. Developers might also use this to support abbreviations that would complete into words that didn't necessarily start with the characters of the abbreviation. The index argument allows delegates or subclasses to return by reference an index specifying which of the completions should be selected initially (default is 0, and -1 means no initial selection).

As the user moves through the list of completions, the following NSTextView method will be called with the currently selected completion:
- (void)insertCompletion:(NSString *)word
forPartialWordRange:(NSRange)charRange
movement:(int)movement
isFinal:(BOOL)final;
for which the default implementation will insert the proposed completion into the text in the appropriate place. The final flag will be NO as long as the completion is still tentative, and YES when the user ultimately picks one completion definitively. The movement argument will describe the action the user took to change the current selected completion; it will take its values from the NSTextMovement enum defined in NSText.h, which already is used for a similar purpose in describing movements through tables, matrixes, and forms. An additional NSCancelTextMovement value has been added, to cover the case in which the user cancels completion and the original partial word is restored. In addition, the movement value 0 has been given the additional name NSOtherTextMovement, which more clearly reflects both its previous and current usage--namely, to cover any case not covered by the other values in this enum. Subclasses will be able to override insertCompletion:forPartialWordRange:movement:isFinal: either to modify the default behavior of the method, or else to perform some additional action, possibly depending on whether and by what means the user has exited the completion process.

One potential source of completions is the spellchecker. In support of this, an additional method has been added to NSSpellChecker:
- (NSArray *)completionsForPartialWordRange:(NSRange)range
inString:(NSString *)string
language:(NSString *)language
inSpellDocumentWithTag:(int)tag;
and the corresponding NSSpellServer delegate method to be implemented in the spellchecker itself:
- (NSArray *)spellServer:(NSSpellServer *)sender
suggestCompletionsForPartialWordRange:(NSRange)range
inString:(NSString *)string
language:(NSString *)language;

Before Panther, text undo/redo operations did not cause NSTextView to send its textView:shouldChangeTextInRange:replacementString: delegate method and its NSTextDidChange notification. On Panther, that delegate method and notification will be send for text undo and redo. However, for compatibility reasons, this will occur only for executables that have been linked on Panther or later system versions.


Bidirectional-savvy Movement

NSResponder methods containing "forward" and "backward" in their names are not the most appropriate choices for arrow key movement in bidirectional text. In Panther, there are some additional methods described by "right" and "left" that are used for binding arrow key movement, and that move in the appropriate visual direction whether it is actually forward or backward in the logical order of the text.
- (void)moveWordRight:(id)sender;
- (void)moveWordLeft:(id)sender;
- (void)moveRightAndModifySelection:(id)sender;
- (void)moveLeftAndModifySelection:(id)sender;
- (void)moveWordRightAndModifySelection:(id)sender;
- (void)moveWordLeftAndModifySelection:(id)sender;


Paragraph Range

We now clearly make a distinction between paragraph separators and line separators. Accordingly, Foundation has new methods on NSString to find paragraph boundaries:
- (void)getParagraphStart:(unsigned *)startPtr
end:(unsigned *)parEndPtr
contentsEnd:(unsigned *)contentsEndPtr
forRange:(NSRange)range;
- (NSRange)paragraphRangeForRange:(NSRange)range;
which parallel the existing line range equivalents, but which take into account only paragraph separators and not all line separators. In usages related to the Cocoa text system, one should decide whether a line range or a paragraph range is the appropriate quantity, and choose from these methods accordingly. The range of an NSParagraphStyle attribute, for example, will always be a paragraph range; likewise, triple-clicking will select a paragraph range.


NSGlyphGenerator

A new public class NSGlyphGenerator has been added to the Cocoa Text System. The class performs the initial nominal glyph generation phase in the layout process. The class communicates via the NSGlyphStorage protocol. An instance of classes conforming to the protocol is NSLayoutManager.

NSGlyphGenerator now generates NSControlGlyph for all characters in the Unicode General Category C* and U200B (ZERO WIDTH SPACE).


NSATSTypesetter

A new public NSTypesetter concrete subclass, NSATSTypesetter, is added in the Cocoa Text System. The class performs the actually layout (determines glyph positions) phase in the layout process.

The NSATSTypesetter API is categorized into 3 groups.

The first group of interfaces declared in the base @interface section itself is divided into 2 sections --- The layout primitives and NSLayoutManager interface.

The layout primitives are usually invoked by NSLayoutManager interface methods internally. In the meantime, the primitives can be called by 3rd party layout engines directly to perform typesetting without using NSLayoutManager.

The second group of API is declared in the NSLayoutPhaseInterface category. It lists all the override points for subclasses in order to tweak various aspects of typesetting behavior.

The third set is declared in the NSGlyphStorageInterface category. The methods are primitives for interfacing with the glyph storage such as NSLayoutManager.

You can override all the methods listed in here to interface with custom glyph storages. Then, calling -layoutParagraphAtPoint: drives each paragraph typesetting session.

The behavior for U00AD (SOFT HYPHEN) now conforms to the Unicode version 4.0 specification.


NSParagraphStyle

The following methods have been added to NSParagraphStyle:
- (float)lineHeightMultiple;
- (void)setLineHeightMultiple:(float)aFloat;
- (float)paragraphSpacingBefore;
- (void)setParagraphSpacingBefore:(float)aFloat;
- (float)defaultTabInterval;
- (void)setDefaultTabInterval:(float)aFloat;
The default values for the lineHeightMultiple, paragraphSpacingBefore, and defaultTabInterval will all be 0.0, which will give the previous behavior. If lineHeightMultiple is positive, then the natural line height will be multiplied by lineHeightMultiple, but still bounded by minimumLineHeight and maximumLineHeight as usual. This means that a lineHeightMultiple of 2.0 will give double spacing. The space between paragraphs will now be the previous paragraph's paragraphSpacing plus the following paragraph's paragraphSpacingBefore. If defaultTabInterval is positive, then tabs after the last explicitly specified tab stop will give effectively left tabs at integral multiples of defaultTabInterval from the left edge of the page.

The remaining three NSLineBreakMode settings, NSLineBreakByTruncatingHead, NSLineBreakByTruncatingTail, and NSLineBreakByTruncatingMiddle, are implemented in NSATSTypesetter (NSTypesetterBehavior > NSTypesetterOriginalBehavior). You can use these to draw truncated strings and text more efficiently that the usual multi-step process (compute size, truncate, then draw).

removeTabStop: used to remove all isEqual: tabstop instances, contrary to documentation. In Panther, for apps linked against Panther or later, it only removes the first isEqual: instance.


NSTextTab

NSTextTab concept is now further generalized. An NSTextTab instance now conceptually consists of two mandatory attributes (tab location and text alignment inside the tab column) and optional attributes represented by a dictionary. This generalization provides increased flexibility in tab settings.


NSResponder

Two new keybinding methods are defined in NSResponder. -deleteBackwardByDecomposingPreviousCharacter: is bound to control-Delete by default. -cancelOperation: is bound to Escape. Also, as described above, we've now added option-Escape as the main default binding for complete:.

NSFontDescriptor

The class NSFontDescriptor has been added, which provides a mechanism to describe a font, which can later be turned into an NSFont object. The main part of the font descriptor is a dictionary of attributes. All attributes are optional. You can currently create a font descriptor using the following methods.
- (id)initWithFontAttributes:(NSDictionary *)attributes;
+ (NSFontDescriptor *)fontDescriptorWithFontAttributes:(NSDictionary *)attributes;
+ fontDescriptorWithName:(NSString *)fontName size:(float)size;
The current attributes that can be defined are
NSFontFamilyAttribute
NSFontNameAttribute
NSFontFaceAttribute
NSFontSizeAttribute
NSFontVisibleNameAttribute
NSFontColorAttribute

NSFont

A new API +[NSFont systemFontSizeForControlSize:] is added.

The font fallback list now respects the user's language precedence list.

NSFont now always flips the text matrix regerdless of its own transformation matrix when set for the focused view that has flipped coordinate system. It used to do so only when the font's transformation matrix was identity. To restore the old behavior, you can set the NSOnlyFlipFontsWithIdentityMatrix preference value to YES.

The -screenFont method now consistently returns the screen font regardless of the receiver's size. The logic to instantiate screen fonts over their printer font counterparts is moved to -[NSLayoutManager substituteFontForFont:]. The new logic in NSLayoutManager now always chooses printer fonts for non-identity matrix fonts.

The default size for the palette font is changed from 10.0 to 11.0 to follow the Aqua specification.

The menu bar font may be different from the font used for menu items. This method returns the font. Passing in 0 for the fontSize returns the default menu bar font.
+ (NSFont *)menuBarFontOfSize:(float)fontSize;
You can get a font descriptor from an NSFont using the following method:
- (NSFontDescriptor *)fontDescriptor;

NSFontManager

The following methods have been added to NSFontManager to support font collection management. You can create and remove collections using the following two methods:
- (BOOL)addCollection:(NSString *)collectionName options:(int)collectionOptions;
- (BOOL)removeCollection:(NSString *)collectionName;
Currently, the only option available for font collections is the
NSFontCollectionApplicationOnlyMask
You can get an array of the current collection names using
- (NSArray *)collectionNames;
and you can get an array of the descriptors in a given collection using
- (NSArray *)fontDescriptorsInCollection:(NSString *)collectionNames;
To add and remove font descriptors from a collection, use the following methods.
- (void)addFontDescriptors:(NSArray *)descriptors  toCollection:(NSString *)collectionName;
- (void)removeFontDescriptor:(NSFontDescriptor *)descriptor fromCollection:(NSString *)collection;
You can get an array of NSFont objects matching a particular font descriptor using the following method. The current implementation only recognizes NSFontFamilyAttribute, NSFontNameAttribute, and NSFontFaceAttribute. All other attributes are ignored.
-(NSArray *) availableFontNamesMatchingFontDescriptor: (NSFontDescriptor *) descriptor;

NSFontPanel

The font collections have migrated to a format that uses the NSFontDescriptor class. The collections now live in ~/Library/FontCollections with the .collection extension. Changes made to the collections using previous versions of AppKit will affect the .fcache files and will not be synched with the new collections. If you want to re-sync them, you will have to remove all the .collection files in the font collections folder and re-launch the font panel.

Font Panel now has the ability to hide elements that are not applicable by having the target respond to a method validating the font panel modes. The following mode masks are defined:
enum {
NSFontPanelFaceModeMask = 1 << 0,
NSFontPanelSizeModeMask = 1 << 1,
NSFontPanelCollectionModeMask = 1 << 2,
...
NSFontPanelStandardModesMask = 0xFFFF, // standard modes, including those added in the future but expected to work by default
NSFontPanelAllModesMask = 0xFFFFFFFF // all modes, including some added in the future but are not enabled by default
};
If the target wants anything other than the standard mode mask, it must respond to this method.
- (unsigned int)validModesForFontPanel:(NSFontPanel *)fontPanel;

Handling of the "Saving" Parameter of the Quit Application Apple Event

In previous versions of Cocoa, the AppKit's default handling of the standard Quit Application Apple event (and the scripting Standard Suite's Quit command) ignored the "saving" parameter, behaving as if its value were always "ask." New behavior has been introduced so that the value of the "saving" parameter is correctly interpreted.

In applications that have an NSDocumentController:

If the value of the "saving" parameter is "yes," each open, modified, document will be sent a -saveDocumentWithDelegate:didSaveSelector:contextInfo: message. If the document is saved successfully, the NSDocument will then be sent a -close message, and the next open, modified, document will be processed. If any document cannot be saved because of an error or user cancellation, the application will not be quit.

For "no," the application will be sent a -terminate: message. The application will not send its delegate an -applicationShouldTerminate: message though.

For "ask," the NSDocumentController will be sent a -reviewUnsavedDocumentsWithAlertTitle:cancellable:delegate:didReviewAllSelector:contextInfo: message, as in previous versions of Cocoa.

In applications that have no NSDocumentController:

If the value of the "saving" parameter is "ask" or "yes," the delegate will be sent an -applicationShouldTerminate:, as in previous versions of Cocoa. Delegates that need to know the exact value of the "saving" parameter can use the the new -[NSAppleEventManager currentAppleEvent] method.

For "no," the application will be sent a -terminate: message. The application will not send its delegate an -applicationShouldTerminate: message though.


Forwarding of Close and Print Scripting Commands Sent to Windows

In previous versions of Cocoa Scripting, close and print commands sent to windows were mishandled. Now, -[NSWindow(NSScripting) handleCloseScriptCommand:] will forward the close command to the corresponding document, if there is a corresponding document and the window is the main window of the document. Otherwise, the window will send itself a -performClose message if it has a close box.

Likewise, [NSWindow(NSScripting) handlePrintScriptCommand:] now forwards the print command to the corresponding document if it is the main window of that document. Otherwise, the window will send itself a -print message.


Obsolete Symbols

NSAlphaEqualToData and NSAlphaAlwaysOne (with values of 1 and 2, respectively) have been removed from NSGraphics.h as they have not been used since before 10.0.





Notes specific to Mac OS X 10.2.5

Jaguar update 10.2.5 contains a new AppKit which addresses a few bugs, including crashers with PNG files containing ColorSync data, corrupt GIF files, and a rare freed memory error in target applications when using accessibility APIs. In addition bug 3163914, causing new style nibs with custom subclasses to cause runtime problems, has also been fixed.

The version number for the AppKit in 10.2.5 is 663.10. A warning though, in very unlikely case you need to distinguish the 10.2.5 version of AppKit --- if treated as a floating point number, 663.10 ends up being less than 663.6.


Notes specific to Mac OS X 10.2.3

A new AppKit is present in 10.2.3. Some of the changes in the 10.2.3 AppKit are listed below.

In case you need to differentiate the two AppKit versions at runtime: The version number for the 10.2.3 AppKit is 663.6. Version number for the 10.2 AppKit was 663. There are no API or header file changes in the AppKit between the 10.2 and 10.2.3.


NSBezierPath

10.2 bug with appendBezierPathWithGlyphs:count:inFont: putting all glyphs on top of each other has been fixed in 10.2.3.


NSColor

NSColor now preserves transparency when printing.


NSColorPanel

The color panel can now display arbitrary copyright information for a color list. To provide copyright information, simply add the NSColorListCopyrightInfo key to your color lists strings file (eg. MyColorList.clr/English.lproj/MyColorList.strings).

The list color picker was updated with several new user features, including a search field.


NSImage

An exception calling a non-existent method clearAvailableData during incremental image loading has been fixed.

JPEG 6 files saved with Graphic Converter could hang or crash applications; this bug has been fixed.

Animated GIF images now work better.


NSOutlineView

A possible crash in calling reloadItem:reloadChildren: during editing is fixed in 10.2.3.


NSTableView

A bug was introduced in 10.2 where calling abortEditing while a cell was being edited could cause a crash. 10.2.3 fixes this problem.

Performance problem with selecting multiple items in a tableview using the keyboard is fixed in 10.2.3.


NSToolbar

Disappearing-menu-items regression in toolbar items with menuFormRepresentations has been fixed in 10.2.3.


NSWindow

Appearance of the top-left corner buttons in metal window titles has changed in accordance with HI spec. Cocoa and Carbon applications which use the framework provided metallic window support will automatically get the new look.


Printing

10.2 regression with programmatically setting custom paper size has been fixed.


Text

Negative tail indents and large negative kerning values now work properly in the new (10.2) typesetter. These fixes make the new typesetter more compatible with the old one.

We have temporarily turned off the inclusion of the Unicode BOM character (0xFEFF) in the Carbon pasteboard type for Unicode text ('utxt') as this was causing problems in a few applications which failed to deal with this properly. It is our intent to reenable this in a future release.

When dragging text, the i-beam cursor will now properly change to an arrow when the drag starts.

A crash in saving as RTF text documents containing glyphs with no corresponding Unicode characters has been fixed in 10.2.3. Such glyphs are usually entered using the character palette.




Notes specific to Mac OS X 10.2

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. Typically we detect where an application was built by looking at the version of Cocoa, AppKit, or Foundation frameworks the application was linked against. Thus, as a result of relinking your application on 10.2, 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.

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 the construct:
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_2
...
#endif
The basic definitions for these come from AvailabilityMacros.h, a new 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_2. However, to see which post-10.1 symbols your app is referencing (for instance), you can build specifying the compiler flag:
-DMAC_OS_X_VERSION_MAX_ALLOWED=MAC_OS_X_VERSION_10_1
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
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 {
    /* 10.2 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

Accessibility

Cocoa's standard user interface elements (e.g. NSButton, NSView, ...) support the newly added Accessibility APIs which allow assistive applications, e.g. a screen reader, to examine and interact with the user interfaces of other applications.

If your application has custom user interface elements you will need to implement the NSAccessibility protocol in order from them to work with the Accessibility APIs. Documentation for this protocol can be found in /Developer/Documentation/Cocoa/TasksAndConcepts/ProgrammingTopics/Accessibility.


Cocoa in Carbon

It is now possible to show Cocoa windows in Carbon applications. When Cocoa is loaded into the Carbon application, NSApplicationLoad() should be called to initialize the Cocoa environment properly. Further documentation for this will be available on the Apple Developer Documentation site.

Font panel and color panel are also available to Carbon applications using Carbon APIs. Cocoa will be loaded dynamically into a Carbon app when needed.


Keyed Archiving

Cocoa now has support for keyed archiving, which allows saving object attributes with keys. This provides a lot more flexibility in the archives, allowing changing the list of attributes an object writes out while maintaining compatibility. Please see the Foundation release notes for details.

Some options you have are:

- If your application writes object archives, and you need those archives to be readable on 10.1, stick to the old format; otherwise it's better to switch over to the new format.
- If your objects implement archiving, and you want them to take advantage of the flexibility and compatibility features provided by keyed archiving, augment your initWithCoder: and encodeWithCoder: methods to implement keyed archiving. Note that objects which do not implement keyed archiving can still be written to keyed archives, but they won't take advantage of the new features.
- When saving nib files in Interface Builder, you can choose to use 10.1 format, 10.2 format, or both. The 10.1 format is compatible with pre-10.2 systems, however, due to compatibility concerns, 10.1 archives are not capable of storing many of the new features added in 10.2 and the future. Saving nib files using the "both" formats allows you to put both the new and old archives into the same .nib wrapper, choosing and opening the appropriate one at runtime. When editing such a nib file, both archives are edited and saved simultaneously.



Localized View of File System

10.2 supports localized view of the file system, which allows users to see names of file system elements (applications, bundles, document packages, and folders) in their primary language, assuming localizations have been provided. This is accomplished without actually localizing the file system names. This feature is discussed further in the System Overview document (near the end of the "How the File System Is Organized" section).

In a Cocoa application, there are several things to be aware of:

- Paths used for file system access are never localized; so the localized versions of file system entity names should only be used when being displayed to the user. For instance, don't use the localized display name when saving paths in preferences or elsewhere.

- Use -[NSFileManager displayNameAtPath:] or the new -[NSFileManager componentsToDisplayForPath:] methods to obtain human-readable names for file system entities, if you display any.

- If you wish your application name to be localizable, add CFBundleDisplayName to your Info.plist. The value of this should be the same as the file system name (without the file extension). This can then be localized via InfoPlist.strings. For performance reasons, it's best not to include this key in Info.plist if your app name is not going to be localized. Note that the existing CFBundleName key (and localization) is still used for the localized "short" application name displayed in the menu bar and about box.

- If you wish to create a folder which has localized names: (1) Provide your folder with the file extension ".localized", and mark the extension as hidden; (2) create a flat bundle called ".localized" in the folder (flat bundles are basically folders with no Contents or Resources subfolders); (3) supply strings files with names such as en.strings, containing "NonlocalizedName" = "Localized name". Example:
Release Notes For My App.localized/
    .localized/
        en.strings (contains "Release Notes For My App" = "Localized name"; )
        ja.strings

Text

Text documents which have a Mac OS type of 'TEXT' and which have no 'styl' resource fork information will be returned as "plain text" from various AppKit attributed string methods which open text files. These used to be identified as rich text. Note that 'TEXT' files with 'styl' info is considered rich text, even if the whole range of text is covered by a single style.

The heuristics for recognizing HTML files based on file contents have changed a bit; files which start with "<--" are no longer considered to be HTML.

With the new support for paragraph spacing, we've discovered some RTF files which had paragraph spacing values set, but of course never displayed up to now. It also turns out due to a Mail bug some text copy/pasted from Mail could have bogus paragraph spacing values. In order to fix these, paragraph spacing values in RTF files generated by Cocoa prior to 10.2 will be ignored by the RTF reader. However, you can use the NSIgnoreRTFParagraphSpacing default to force the behavior one way or the other (never ignore, always ignore). Note that as a part of this fix, the value of the CocoaRTFVersion document attribute was bumped up from 100 to 102.

We now read/write -[NSParagraphStyle lineSpacing] (the space between lines within a paragraph, aka leading) in RTF files.

The major text system objects (NSTextView, NSTextContainer, NSLayoutManager, and NSTextStorage) now support archiving using the new keyed archiving. This allows arbitrary configurations of the text system to be archived.

Menu items with the action paste: now automatically disable themselves when the first responder is an NSTextView and there is nothing in the pasteboard currently that can be pasted into the NSTextView.


NSParagraphStyle

NSParagraphStyle now has methods for the base writing direction setting in bi-directional text. -[NSParagraphStyle baseWritingDirection] and -[NSMutableParagraphStyle setBaseWritingDirection:] are the accessor methods for the attribute. You can use +[NSParagraphStyle defaultWritingDirectionForLanguage:] to query the default writing direction for a given localization name. Passing nil implies the user's default setting.

Tab stops other than left (right, centered, and decimal) are now implemented.


NSAttributedString

NSAttributedString's text break methods: -[NSAttributedString lineBreakBeforeIndex:withinRange:], -[NSAttributedString doubleClickAtIndex:], and -[NSAttributedString nextWordFromIndex:forward:], now have Unicode compliant implementations.

For backward compatibility, -lineBreakBeforeIndex:withinRange: still returns the index passed in the first argument when the index equals to the string length.


NSGlyphInfo

We now have a new class, NSGlyphInfo. Instances of this class are used to represent glyphs in attributed strings, allowing you to override the font specified Unicode -> glyph ID mapping. For example, you can specify a variant glyph for character 'a' if the font contains multiple variations for the character with this API. Or you can specify a certain ligature glyph that doesn't have a Unicode mapping. The following example assigns the small capital letter 'A' glyph often found in OpenType fonts.
NSMutableAttributedString *attrString; // Pre-initialized attributed string
NSRange rangeOfStringToBeOverriden;
NSString *baseString = [[attrString string] substringWithRange:rangeOfStringToBeOverriden];
NSFont *font = [attrString attribute:NSFontAttributeName
atIndex:rangeOfStringToBeOverriden.location
effectiveRange:NULL];
NSGlyphInfo *smallCapitalAGlyph = [NSGlyphInfo glyphInfoWithGlyphName:@"Asmall"
forFont:font
baseString:baseString];
[attrString addAttribute:NSGlyphInfoAttributeName
value:smallCapitalAGlyph
range:rangeOfStringToBeOverriden];

NSTextInput protocol

The InkWell text input service can ask you to return the content of your text input client that extends to your document range; so the implementation for the NSTextInputProtocol method, -attributedSubstringFromRange:, should be prepared to get out-of-bounds range. In that case, you should return the intersection of your document range and the range specified in the argument. If the location of the range is completely out-of-bounds of your document range, you can return nil.


NSTypesetter

We now have a new, currently private, NSTypesetter subclass which is enabled as the default system typesetter. It utilizes the Apple Type Service for Unicode Imaging functionality extensively, providing applications with advanced typography features such as smart-quoting and context-sensitive swashes, and broadening the support for languages in the AppKit framework.

In order to provide the reliable text layout compatibility between Mac OS X releases for applications, the AppKit text subsystem has new APIs to control various aspects of the text layout management in the framework.

NSLayoutManager now has the new methods:
- (NSTypesetterBehavior)typesetterBehavior;
- (void)setTypesetterBehavior:(NSTypesetterBehavior)behavior;
NSTypesetterBehavior is defined as:
typedef enum {
NSTypesetterLatestBehavior = -1,
NSTypesetterOriginalBehavior = 0,
NSTypesetterBehavior_10_2_WithCompatibility = 1,
NSTypesetterBehavior_10_2 = 2,
} NSTypesetterBehavior;
Setting the NSTypesetterLatestBehavior value causes the layout manager to use the latest (most-advanced) typesetter available on the system. This is the default value, and is appropriate for most usages. On 10.2, this corresponds to NSTypesetterBehavior_10_2. This enables all the new features in the new typesetter and fixes bugs in the NSSimpleHorizontalTypesetter implementation:

- It doesn't add the extra one pixel to the default ascender caused by a floating-point rounding error found in the previous typesetter implementation
- The values returned from -[NSParagraphStyle firstLineHeadIndent] and -[NSParagraphStyle headIndent] are interpreted as expected with all text alignment modes
- The value returned from -[NSParagraphStyle paragraphSpacing] is used by the typesetter
- It doesn't add the extra 20% leading to the ascender anymore except with Helvetica, Times, Courier that are already commonly used in the user interface.
- It interprets the value in NSBaselineOffsetAttributeName even if the attribute is set to the whole paragraph.

NSTypesetterBehavior_10_2_WithCompatibility behaves just as NSTypesetterBehavior_10_2 except the bugs listed above are preserved for applications that want to use the new typesetter and are relying on the behavior in the NSSimpleHorizontalTypesetter implementation.

NSTypesetterOriginalBehavior provides 100% compatibility by using the NSSimpleHorizontalTypesetter. You will not get the new features.

There are 2 default settings to control the default typesetter behavior: "NSTypesetterBehavior" takes integer values from 0 to 2 corresponding to the enumerated values in the NSTypesetterBehavior type. Other values are interpreted as NSTypesetterLatestBehavior. The default value for applications built on 10.2 is NSTypesetterBehavior_10_2, and the default value for applications built on prior versions is NSTypesetterOriginalBehavior. The value is accessible via the new NSTypesetter class method +defaultTypesetterBehavior.

"NSStringDrawingTypesetterBehavior" takes integer values from 0 to 2 corresponding to the enumerated values in the NSTypesetterBehavior type. Other values are interpreted as NSTypesetterLatestBehavior. This is the value used by the string drawing methods and NSCell subclasses. When this key is not present in the default database, it uses the value for NSTypesetterBehavior, assuming the value explicitly set and is smaller than the default value for NSStringDrawingTypesetterBehavior. The default value for NSStringDrawingTypesetterBehavior for applications built on 10.2 is NSTypesetterBehavior_10_2_WithCompatibility, and the default value for applications built on prior versions is NSTypesetterOriginalBehavior.

Using the new NSLayoutManager method, -defaultLineHeightForFont, applications can query the initial line height used by the typesetter subclasses depending on the current typesetter behavior in the receiver. It is no longer necessary to query the size of string containing a single space in order to get the line height for an empty string. This method returns the exact value used by the typesetters.

In NSTypesetterBehavior_10_2 and NSTypesetterBehavior_10_2_WithCompatibility, a new Unicode 3.2-based overstruck glyph inscription algorithm is used. It covers all the combining characters defined in the character standard, except the ones in Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, Malayalam, Sinhara, Thai, and Myanmar (U0900 - U0E7F and U1000 - U109F). The combining characters in these scripts require fonts with Apple Advanced Typography capabiliity. The new typesetter tries to precompose before falling back to the attachment placement algorithm based on the combining class, resulting in better glyph substitution with fonts that lacks the Apple Advanced Typography tables. There is now a threshold for the number of consecutive overstruck glyphs. A character sequence that has more combining characters than this threshold is not precomposed. The default value is 10 glyphs. The setting can be overriden via the "NSMaxNonBaseInscriptionGlyphs" default value.

Known issues with NSTypesetterBehavior_10_2 and NSTypesetterBehavior_10_2_WithCompatibility:

- The NSGlyphInscription values other than NSGlyphInscribeBase and NSGlyphInscribeOverstrike are ignored
- Two Apple Advanced Typography features, the context-senstive justification and left/right hangers, are explicitly disabled in this release.


NSInputManager

By default, NSInputManager no longer searches /Network/Library/InputManagers for input managers. You can override this behavior by setting the user preference NSSearchNetworkForInputManagers to YES in order to load input managers over the network.


NSFont

A new API, -coveredCharacterSet, is added to NSFont. It returns an NSCharacterSet that contains all the nominal characters renderable by the receiver. In other words, it returns all the entries mapped in the font's 'cmap' table. Note that the number of glyphs supported by a given font is often larger than the number of characters contained in the character set returned by this method. For example, a font may have a 'tt' ligature glyph, but it won't be in the character set since the glyph doesn't have the corresponding Unicode Value.


NSFontPanel

The font panel now has an optional preview pane, which can be shown by the user. It remembers its size on a per-app basis.


NSColorPanel

The standard color panel now has a "crayon" mode that offers the user a set of predefined colors to choose from. The crayon colors are also accessible in the "list" picker, by choosing "Crayons" in the "Palette" pop-up button. Two new constants have been added to NSColorPanel.h to accommodate this new color picking mode:
    NSCrayonModeColorPanel        = 7
NSColorPanelCrayonModeMask    = 0x00000080

The "Apply" button has been removed from the color panel. The NSColorPanel used to call the responder method 'changeColor:' whenever this button was clicked. Since the button is no longer there, 'changeColor:' will be sent to the first responder immediately on a color change. This responder method will be sent continuously only if the color panel is set to be continuous.


If you have written a custom color picker, you should check to make sure your picker fits into the area available at the new color panel's minimum size. If the view provided by your color picker is not resizable (this applies to width and height), then the color panel will automatically force itself to be at least big enough to accommodate your view in its full size.


In the past, the color panel used a matrix of buttons to present as a matrix of buttons. The color panel now uses a small icon only toolbar. So, you should make sure your icon looks good as a small toolbar icons (see NSToolbarItem relnotes for more information). Note that in the past, the button image and the tooltip could be supplied by overriding -provideNewButtonImage and/or -insertNewButtonImage:in:. This is still the case.


NSProgressIndicator

10.2 brings support for a spinning style in addition to the current bar style. The following API has been added to support this new style.
typedef enum {
NSProgressIndicatorBarStyle = 0,
NSProgressIndicatorSpinningStyle = 1
} NSProgressIndicatorStyle;
- (void) setStyle:(NSProgressIndicatorStyle)style;
- (NSProgressIndicatorStyle)style;
// For the spinning style, it will size the spinning arrows to their default size.
// For the bar style, the height will be set to the recommended height.
- (void) sizeToFit;
// True by default; for spinning style, might make sense to choose
// to have it not displayed when stopped.
- (BOOL) isDisplayedWhenStopped;
- (void) setDisplayedWhenStopped:(BOOL)isDisplayed;

NSDocumentController

NSDocumentController attempts to create a new document at application launch time using the first suitable document type declared in the application's Info.plist file, if there is one. In previous releases of Mac OS X, a document type was considered suitable if its Info.plist dictionary contained a CFBundleTypeRole entry whose value was "Editor" or "Viewer." Due to the widespread confusion this caused among developers who were using Cocoa's document architecture to write viewer-only applications, this behavior has been changed. Now, NSDocumentConroller will attempt to create a new document at launch time using the first type whose Info.plist dictionary's CFBundleTypeRole entry is "Editor," if there is one. Document types for which the application can only assume the "Viewer" role will not be considered.

For backwards binary compatibility, NSDocumentController will exhibit the same behavior in this regard as it did in Mac OS 10.1, when running in programs that were linked against the 10.1 or earlier versions of the AppKit or Cocoa frameworks.


In previous releases of Mac OS X, -[NSDocumentController typeFromFileExtension] compared passed-in file name extensions to the extensions declared in the application's Info.plist in a case-sensitive manner. As a result, NSDocument-based applications were often unable to open documents with file name extensions cased in a manner unanticipated by application developers. For example, documents with a file name extension of "PDF" could not be opened by an application whose Info.plist contained a CFBundleTypeExtensions array that contained only a "pdf" entry. This bug has been fixed. Some developers worked around it by redundantly listing file name extensions in their application's Info.plist, with the redundant entries varying only by character case. Such a workaround is no longer necessary for applications that are not required to run on releases of Mac OS X older than 10.2.


NSPrinter

Some NSPrinter methods have been deprecated. They are:
- (NSRect)imageRectForPaper:(NSString *)paperName;
+ (NSPrinter *)printerWithName:(NSString *)name domain:(NSString *)domain includeUnavailable:(BOOL)flag;
- (NSString *)domain;
- (NSString *)host;
- (NSString *)note;
- (BOOL)acceptsBinary;
- (BOOL)isColor;
- (BOOL)isFontAvailable:(NSString *)faceName;
- (BOOL)isOutputStackInReverseOrder;
See the comments in the <AppKit/NSPrinter.h> header file more more specific information.


In previous releases of Mac OS X, -[NSPrinter printerNames] returned the names of all NetInfo-registered printers, regardless of whether the printers had been added to the Print Center's Printer List. This behavior has been changed. -[NSPrinter printerNames] now returns the names of the same printers that appear in the printer list.

In previous releases of Mac OS X, -[NSPrinter printerTypes] always returned an array that contained exactly one string ("Xrn4525p"). It now returns strings that contain the makes and models of the printers that appear in the printer list.


NSPrintInfo

It is important in many applications to be able to reliably determine the maximum imageable area of a printed page. A new method has been added to NSPrintInfo:
- (NSRect)imageablePageBounds;
Returns the imageable area of a sheet of paper specified by this object, taking into account the current printer, paper size, and orientation settings, but not scaling. "Imageable area" is the maximum area that can possibly be marked on by the printer hardware, not the area defined by the current margin settings. The rectangle is in a coordinate space measured by points, with (0, 0) being the lower-left corner of the oriented sheet and (paperWidth, paperHeight) being the upper-right corner of the oriented sheet. The imageable bounds may extend past the edges of the sheet when, for example, a printer driver specifies it so that borderless printing can be done reliably.


Some NSPrintInfo methods have been deprecated. They are:
+ (void)setDefaultPrinter:(NSPrinter *)printer;
+ (NSPrinter *)defaultPrinter;
+ (NSSize)sizeForPaperName:(NSString *)name;
Also, some NSPrintInfo attributes have been deprecated. They are:
NSPrintFormName
NSPrintJobFeatures
NSPrintManualFeed
NSPrintPagesPerSheet
NSPrintPaperFeed
See the comments in the <AppKit/NSPrintInfo.h> header file more more specific information.


Printing Presets

New since WWDC update of 10.2, Mac OS X now has support for "printing presets". With this feature, printer drivers can specify names for commonly used sets of printing parameter values, so users can select such sets easily. For example, when this feature is enabled, and when a printer that supports this feature is selected, the user might see items like "Photo on Plain Paper" in the Presets menu of print panels. To enable this feature, applications must provide a hint about what kind of print job is being output. New methods have been added to Cocoa for this.

Right now, only one style of print job is supported. It is identified by a constant string that has been added to NSPrintPanel.h. It's declaration looks like this:
NSString *NSPrintPhotoJobStyleHint;
This is currently the only valid value for identifying a job style hint.

Two new methods have been added to NSPrintPanel.h:
- (void)setJobStyleHint:(NSString *)hint;
- (NSString *)jobStyleHint;
Sets or gets a string that provides a hint about the type of print job in which the print panel is being used. This controls the set of items that appear in the Presets menu. Currently, the string must be NSPrintPhotoJobStyleHint, or nil to provide no hint.

Matching methods have been added to NSPrintOperation.h:
- (void)setJobStyleHint:(NSString *)hint;
- (NSString *)jobStyleHint;
Sets or gets a string that provides a hint about the type of print job. This controls the set of items that appear in the Presets menu of the print panel presented by this operation, if it presents one. Currently, the string must be NSPrintPhotoJobStyleHint, or nil to provide no hint.


NSWindow

-[NSWindow setBackgroundColor:] will now take effect regardless of the window styleMask. In 10.1, -[NSWindow setBackgroundColor:] only modified the background color for borderless windows (that is, windows with styleMask equal to NSBorderlessWindowMask).

There is now a styleMask to specify that a window has a textured background, NSTexturedBackgroundWindowMask. Windows with this styleMask get a metal-textured background similar to the background in iApp windows. A window with this styleMask may be moved by clicking and dragging anywhere in the window background, as opposed to a window without this styleMask which may only be moved by clicking and dragging in the titlebar. A bordered window with this styleMask will also get rounded bottom corners. A borderless window may also be given this styleMask to specify that it should have the metal-textured background and be movable by the window background.

There is now a method to specify that a custom window should be movable by its background, and a method to query this setting. A window whose styleMask includes NSTexturedBackgroundWindowMask gets this setting by default, except that it is not allowed for sheets and drawers.
- (void)setMovableByWindowBackground:(BOOL)flag;
- (BOOL)isMovableByWindowBackground;
Also see discussion of -[NSView mouseDownCanMoveWindow] further below.


Keyed archiving for NSWindow is an illegal operation. An attempt to archive or unarchive NSWindow using a keyed coder will raise an NSInvalidArgumentException.


The following NSWindow changes are new since WWDC release of 10.2.

The -windowRef method has been modified to create a Carbon WindowRef if one does not already exist for the window. This method previously returned a WindowRef only for an NSWindow created using -initWithWindowRef:. -windowRef can now be used to create a WindowRef for a window containing a Carbon control. Subsequent calls to the method will return the existing WindowRef.


There is new API to create and access the buttons in the window titlebar:
typedef enum {
    NSWindowCloseButton,
    NSWindowMinimizeButton,
    NSWindowZoomButton,
    NSWindowToolbarButton,
    NSWindowDocumentIconButton
} NSWindowButton;
The following method returns an autoreleased new instance of the given standard button, sized appropriately for the styleMask. The caller is responsible for adding the button to the view hierarchy and for setting the target to be the window:
+ (NSButton *)standardWindowButton:(NSWindowButton)b forStyleMask:(unsigned int)styleMask
The following returns the given standard button if it is in the window view hierarchy:
- (NSButton *)standardWindowButton:(NSWindowButton)b

There is new API to attach one window to another for purposes of moving and ordering. childWin will be ordered either above (NSWindowAbove) or below (NSWindowBelow) the receiver, and maintained in that relative position for subsequent ordering operations involving either window. While this attachment is active, moving childWin will not cause the receiver to move (as in sliding a drawer in or out), but moving the receiver will cause childWin to move:
- (BOOL)addChildWindow:(NSWindow *)childWin ordered:(NSWindowOrderingMode)place
To query the array of attached child windows:
- (NSArray *)childWindows
To detach childWin from the receiver:
- (void)removeChildWindow:(NSWindow *)childWin
To get the parent window to which the receiver is attached as a child:
- (NSWindow *)parentWindow
Bottleneck for setting the parentWindow ivar in the receiver. May be overridden by subclasses; should call super:
- (void)setParentWindow:(NSWindow *)window
Note that ordering operations on the child will also effect the parent, so a child window should generally be removed from its parent before the childWindow is ordered out.


There is now API to make a window transparent to mouse events, allowing overlay windows. To set whether the window is transparent to mouse clicks and other mouse events, allowing overlay windows:
- (void)setIgnoresMouseEvents:(BOOL)flag;
Return whether the window is transparent to mouse events:
- (BOOL)ignoresMouseEvents;
If a custom-shaped window has a shadow, the shadow must be updated when the window changes shape. The following method will invalidate the window shadow so that it will be recomputed based on the current window shape:
- (void)invalidateShadow;

NSPanel

10.2 brings the concept of a non-activating panel. A non-activating panel can receive keyboard input without activating its owning application. To support this, a styleMask has been added to NSPanel.h:
enum {
    ...
NSNonactivatingPanelMask = 1 << 7
};
This styleMask can be passed to NSPanel's designated initializer:
- (id)initWithContentRect:(NSRect)contentRect styleMask:(unsigned int)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag;
Note that like NSUtilityWindowMask, NSNonactivatingPanelMask is only valid for an NSPanel or subclass, it is not valid for an NSWindow.

This type of panel inherits NSPanel's method for specifying whether the panel should become key when activated, or only if needed:
- (BOOL)setBecomesKeyOnlyIfNeeded:(BOOL)flag;
If this method is called with YES, then the non-activating panel becomes key only if the hit view returns YES for -needsPanelToBecomeKey. In this way, a non-activating panel can control whether it steals keyboard focus or not. Internally, we will allow keyboard events to be routed to a panel without requiring the owning application to be active. A non-activating panel with keyboard focus will have the appearance associated with key windows, including focus rings, cursor rects, and a blinking cursor if appropriate. A non-activating panel can be made key even if its owning application is not active.


NSView

NSView's autosizing machinery no longer adjusts the y origin to 0 when it becomes negative. In the prior releases, NSView used to adjust the y origin to 0 when it becomes negative, often resulting in inaccessible views pushed outside the window. The adjustment behavior is removed when the vertical autoresizingMask is NSViewMinYMargin.

The long-standing bug with drifting of autoresized views (usually set via springs in IB) has been fixed. Note that this fix applies to views whose frames do not overlap the edges of their superviews; in general autoresizing flags are not designed to work well otherwise.


New since the WWDC update of 10.2, NSView now has a new method which allows a view to specify whether or not it should be treated as blocking window moving for a mouseDown in its bounds. This only applies to views in windows that return YES for -isMovableByWindowBackground. The default implementation returns YES if the view is not opaque and NO otherwise. NSControl and other standard views that implement mouseDown: return NO for this method. A custom view should implement this method to return NO if it wants to disable window moving for a mouseDown: within the view bounds. This is an addition to NSView.h:
- (BOOL)mouseDownCanMoveWindow;

NSResponder

A method has been added to NSResponder in order to distinguish when a pen-down should start inking vs. when it should be treated as a mouse down event. This is needed to support a write-anywhere model for pen-based input.
- (BOOL)shouldBeTreatedAsInkEvent:(NSEvent *)event;
The event argument is the mouse down with tablet data. This method returns YES if the event should be treated as an ink event, NO if it should be treated as a mouse event.

A pen-down causes this method to be sent to NSApplication. The default implementation in NSApplication sends the method to the NSWindow under the pen. If the window is inactive, -shouldBeTreatedAsInkEvent: returns YES, unless the pen-down is in the window drag region.

If the window is active, -shouldBeTreatedAsInkEvent: will be sent to the NSView under the pen. The default implementation in NSView returns YES, and NSControl overrides to return NO. This allows write-anywhere over most NSViews, but also allows the pen to be used to track in controls and to move windows.

A custom view should override this method if needed to get the correct behavior for a pen-down in the view.


HFS Promises

Cocoa now supports dragging of HFS Promises for both the drag source and the drag destination. This has been added since WWDC release of 10.2.

An NSView that acts as a dragging source for HFS promises should call -[NSView dragPromisedFilesOfTypes:fromRect:source:slideBack:event:]. This method will write a new pasteboard type, NSFilePromisePboardType, with data consisting of the fileTypes array, and will also write a private type necessary to allow the destination to ask for the filenames when the drag is dropped. This is an addition to NSView.h:
- (BOOL)dragPromisedFilesOfTypes:(NSArray *)fileTypes fromRect:(NSRect)aRect source:(id)sourceObject slideBack:(BOOL)slideBack event:(NSEvent *)theEvent
fileTypes - an array of file type extensions, eg. [NSArray arrayWithObject:@"txt"] to promise one file with a .txt extension, or [NSArray arrayWithObjects:@"pdf", @"pdf", nil] to promise two files with the .pdf extension. It is also be possible to promise HFS types, using NSFileTypeForHFSTypeCode.
aRect - describes the position of the dragged image representing the file promise
sourceObject - the controller of the dragging operation, which must conform to the NSDraggingSource protocol
slideBack - whether or not the dragged image should slideback if the drag is rejected
theEvent - the mouse-down event object from which to initiate the drag operation

This method returns     YES if the drag operation is successfully initiated, NO otherwise.

When the drag is dropped on a destination that accepts HFS promises, -namesOfPromisedFilesDroppedAtDestination: will be invoked on the sourceObject. This is an addition to the NSDraggingSource informal protocol:
 -(NSArray *)namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination
dropDestination - a URL representing the drop location

This returns an array of filenames for the created files - note that this is filenames only, not full paths.

A dragging source will use the -[NSView dragPromisedFilesOfTypes:fromRect:source:slideBack:event:] to promise one or more files for dragging, but will defer creation of these files until after the drag has been dropped, so that the promised files can be created at their final destination. The actual contents of the files should not be written until after the drag has been released if the files are large, to prevent blocking the destination during a lengthy file operation. In addition, a source can promise a top-level directory, then fill in the directory contents after the drag has been released.

The destination may be either Carbon or Cocoa. If the destination is Cocoa, -performDragOperation: is called on the destination when the drag is dropped. At this point, the destination should call a new method on NSDraggingInfo to get the names for the promised files, passing the destination of the drop. This is an addition to the NSDraggingInfo protocol:
 -(NSArray *)namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination
dropDestination - a URL representing the drop location

Returns an array of filenames for the created files - note that this is filenames only, not full paths

This will cause an IPC to the source which will invoke -namesOfPromisedFilesDroppedAtDestination: on the dragging source if the source is Cocoa, or will ask for the HFS promise data if the dragging source is Carbon.


NSPasteboard

The -changeCount method now returns an integer which only changes when the entire set of data on the pasteboard changes. This aligns with the documented behavior. It used to return an integer which changed whenever anything on the pasteboard changed.

-declareTypes:owner: now properly returns the change count of the pasteboard. This aligns with the documented behavior. It used to return 0.

-addTypes:owner: now properly returns the change count of the pastebaord. This aligns with the documented behavior. It used to return -1 or 0.

The -dataForType: method now waits for a longer time for promises to be fulfilled, either the integer seconds given by the NSPasteboardPromiseTimeout default, or 120 seconds if the default does not exist.


AppKit has added a new constant, NSVCardPboardType, to represent VCards on the pasteboard. The AppKit doesn't do anything with data of this type, it is just exporting the type for clients.


Pasteboard Server Lookup Timeouts

The timeout for pbs server operations has been increased quite a bit, which may cause applications to hang longer in certain cases, and hopefully eventually get through, rather than simply fail.

There are three defaults that control the various timeouts. The values of the defaults should be integers, in units of seconds. Most of the time these defaults are sufficient, and apps need not worry about them

    NSPBSServerLookupTimeout    default: 10 seconds
    NSPBSServerSendTimeout        default: 20 seconds
    NSPBSServerReplyTimeout        default: 60 seconds


NSSound

NSSound now uses QuickTime to play most sound files/URLs, including streaming non-file URLs from the Internet. Since QuickTime requires the run loop to be run for sound (or movies) to continue playing, NSSound now requires this as well. The delegate -sound:didFinishPlaying: will also not be called unless the run loop is run. By "run loop", what is meant is the run loop on the thread which starts the sound playing. For Cocoa applications, this is not a big deal for sounds played by the main thread, as Cocoa apps normally let the AppKit handle running the run loop on the main thread. But in other situations you will need to be aware of this requirement.


NSEvent

In 10.2, and since the WWDC seed, the window server started setting an additional device-dependent modifier flag in user input events to indicate when event coalescing is disabled. Applications that check for modifierFlags using equality without masking off the device-dependent modifierFlags first can get unexpected behavior due to this change. In order to maintain compatibility for applications built on 10.2 and earlier systems, NSEvent by defaults strips this device-dependent modifier flag when creating the event from a windowServer event. For applications built on systems later than 10.2, this will no longer be the default behavior. In order to override NSEvent's default behavior, an application can specify a value for the user default NSDeviceDependentModifierFlags. If this default is set to YES, the device-dependent modifier flags will not be stripped.


NSWorkspace

NSWorkspace now contains two additional methods for dealing with the list of running applications. For the purpose of these methods, an application is specified by returning a dictionary with as many of the following keys as are available:

NSApplicationPath (the full path to the application, as a string)
NSApplicationName (the application's name, as a string)
NSApplicationProcessIdentifier (the application's process id, as an NSNumber)
NSApplicationProcessSerialNumberHigh (the high long of the PSN, as an NSNumber)
NSApplicationProcessSerialNumberLow (the low long of the PSN, as an NSNumber)

In addition, these keys have been added to the userInfo dictionary for the NSWorkspace application will launch, did launch, and did terminate notifications.

The new methods are:
- (NSArray *)launchedApplications;
- (NSDictionary *)activeApplication;
The first of these returns an array of these dictionaries for all running applications (those for which a will launch notification would have been sent), while the second returns a dictionary for the current frontmost application.


NSSavePanel

If -setTreatsFilePackagesAtDirectories: was sent to the save panel while it was on screen, the browser would get in an invalid state and not update properly to the new state of the panel. The user had to "click around" in the browser to get it updated. This has been fixed. This allows -setTreatsFilePackagesAtDirectories: to be called, for example, as the result of the user toggling a switch in the accessory view of the panel.


Accessory Views are now part of the keyboard loop (NSColorPanel, NSSavePanel, NSOpenPanel, spell checking panel)

Many system panels allow developers to specify a custom accessory view to be displayed as part of the panel. In previous version of Mac OS X, those accessory views did not become part of the panels keyboard loop. This has been fixed for a few system panels, including: NSSavePanel, NSOpenPanel, NSColorPanel, and the shared spell checking panel. You can specify your own keyboard loop within the accessory view. These system panels treat the accessory view's 'nextKeyView' much like an initialFirstResponder of an NSWindow (see notes in NSWindow on automatically generated keyboard loops). If the view's nextKeyView is not set, it will be assumed you have not specified your own keyboard loop, and one will be computed for you. If a 'nextKeyView' is set, then your loop will be used. Normally the automatically computed keyboard loop will do what you want.


NSTabView

NSTabView now has support for directional tabs - NSLeftTabsBezelBorder, NSBottomTabsBezelBorder, and NSRightTabsBezelBorder tab view types are now implemented. These styles can be chosen in InterfaceBuilder, or by calls to -setTabViewType:. One can check for support of this new feature by comparing against the constant:
    #define NSAppKitVersionNumberWithDirectionalTabs 631.0
No new API has been introduced to support directional tabs. However, there are issues with some existing API that require explanation.

First, define the normal axis to be the one given by the direction of the tab. So, for NSRightTabsBezelBorder tabs, the normal axis points east, or left to right across the screen. Next, define the label axis to be perpendicular to the normal axis. The width of the label is always measured along the label axis, and the height along the normal axis. Given these definitions, we clarify the effect on existing APIs:
    NSTabViewItem:
    - (void)drawLabel:(BOOL)shouldTruncateLabel inRect:(NSRect)labelRect;
     // This method draws the tab label in labelRect.
     // 'labelRect' is the area in between the curved end caps.
     // 'shouldTruncateLabel' is a hint that the label should be truncated.
    - (NSSize)sizeOfLabel:(BOOL)computeMin;
     // This method returns the minimum or nominal size of the tab label.
     // 'computeMin' indicates whether you should return the minimum or
     // nominal label size. The returned value is used to
     // compute the range of legal sizes for the tab label.
-drawLabel:inRect: assumes the label and normal axis are along the x and y axis respectively. This method is called by NSTabView after transforming the coordinate system to achieve this effect. So, by default developers can draw all tabs as if they were north facing (NSTopTabsBezelBorder).

-sizeOfLabel: also returns the width and height of the items label. The width of the label is measured along the label axis, and the height is measured along the normal axis.


NSBrowser

Mouse clicks in a browser that doesn't accept first responder no longer cause the current first responder to resign.

Browsers no longer enclose their titles within the focus ring rectangle. The focus ring will always enclose just the columns (and horizontal scroller if present).


NSTableColumn

A bug was discovered in 10.1 which could not be fixed in 10.2. Table columns created in IB have data cells with different properties than those created with alloc/init. NSTableColumns that come from IB (Either straight from the palette, or made via copy paste), will contain a NSTextFieldCell whose drawsBackground property is NO, and whose font is 13 pt. Lucida Grande. When a NSTableColumn is created using [[NSTableColumn alloc] initWithIdentifier:@"foo"], it will contain a NSTextFieldCell whose drawsBackground property is YES, and whose font is 12 pt. Lucida Grande. Until this is fixed, it may be necessary to verify / fix the font heights of your tables in code.


NSColor

isEqual: on pattern colors will now properly return NO with arguments which are not colors. This used to raise an exception.


colorWithPatternImage: used to return non-autoreleased colors. For apps linked post-10.1, this will correctly autorelease the return value. If you were not retaining the return value, your app will crash once it's linked on a post-10.1 system. The fix is to retain the color. If you need to dynamically check this fix, look for AppKit version >= NSAppKitVersionNumberWithPatternColorLeakFix (or if your use of pattern colors is small --- just a few instances allocated --- let the 10.1 version leak).


NSColor now has the following additional standard colors. These parallel the existing selectedControlColor and selectedControlTextColor:
+ (NSColor *)alternateSelectedControlColor;
+ (NSColor *)alternateSelectedControlTextColor;
These colors are meant to be used in tables and lists where Mail or iTunes like highlighting is desired. For inactive items in these situations, use the existing methods secondarySelectedControlColor and selectedControlTextColor. Note that in this context inactive does not mean disabled; it means non-key (aka secondary).

See below ("Alternate Selection Colors") for discussion on use of these colors in the AppKit.


Alternate Selection Colors

The highlight coloring scheme for lists and browsers has been changed. The goal is to make it easier to tell which control has keyboard focus. The new scheme, which applies to selections and their text, should be picked up automatically for most. However, some work may be required for adoption. Here's a summary of how the highlighting scheme works:

When a table/outline or browser is actively focused (the control receiving keyboard events, ie. it is first responder and in the key window), they will show selections using the new alternate highlight color, +[NSColor alternateSelectedControlColor]. For browsers, only the last column will use +[NSColor alternateSelectedControlColor] . In 10.1, +selectedControlColor was used.

If a table/outline or browser is not actively focused then it uses +[NSColor secondarySelectedControlColor]. For browsers, this color is used for every column except the last selected column. This process is the same as it was in 10.1; however, the color value has changed. It used to be a lighter version of +[NSColor selectedControlColor], now it is simply a light gray. (And clearly it could change in the future, so please, no assumptions.)

If a row is highlighted using +[NSColor alternateSelectedControlColor], NSCell will automatically use +[NSColor alternateSelectedControlTextColor] instead of +[NSColor controlTextColor] when drawing. Automatic use of the alternate text color will only happen if your cell's text color is set to +[NSColor controlTextColor], or your text color's RGB values are the same as +[NSColor controlTextColor]. Also, NSCell will not change your cell's stored text color. It simply will decide to draw with a different color if appropriate.

Adopting the new highlighting scheme:
- Most will not have to do anything for this to work.
- If you draw some of your own table/outline, browser, or cell highlights you should verify that they still look fine. If they do not, it is probably because you are hard-coding your use of colors. When drawing highlights, it is recommended that you ask NSCell what color to use by calling -highlightColorWithFrame:inView:.
- If you do your own text drawing (using string drawing routines), or set your own text colors, make sure the correct colors are being used as appropriate. Since it is common to subclass NSCells and do this, below is an example of how to do text highlighting.

If you can not use the alternate colors for some reason you can set the NSAlternateListHighlightCompatibility_10_1 default to YES.
    - (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
NSColor *highlightColor = [self highlightColorWithFrame:cellFrame inView:controlView];
BOOL highlighted = [self isHighlighted];
        if (highlighted) {
    [highlightColor set];
NSRectFill(cellFrame);
}
        // Draw the icon
        if (myImage) {
            .....
        }
        // Draw the text (myTitle is an NSAttributedString)
        if (myTitle) {
            // If we are highlighted AND are drawing with the alternate color, then we want to draw our text with the alternate text color.
// For any other case, we should draw using our normal text color.
            if (highlighted && [highlightColor isEqual:[NSColor alternateSelectedControlColor]]) {
                // Make a copy of our title so that we can ....
NSMutableAttributedString *myTitleCopy = [[myTitle mutableCopy] autorelease];
                // ... add the alternate text color attribute...
[myTitleCopy addAttribute:NSForegroundColorAttributeName
                    value:[NSColor alternateSelectedControlTextColor]
range:NSMakeRange(0,[myTitle length])];
myTitle = myTitleCopy;
            }
            // Draw the text
            [myTitle drawInRect: .....];
        }
    }


NSTableView

Any API that changes the selection in a table view will now end editing if it is appropriate. For example deselectAll: will always end editing. In general if calling the API causes the edited row to no longer be selected, editing will be ended. Further, if calling the API causes multiple rows to be selected, editing will be ended. In all cases editing is ended gracefully, meaning the value will be applied if it is valid.

The image passed to setIndicatorImage: is now retained and released by the table view as appropriate.

The default sorting order indicators are now available as named NSImages. These images can be accessed with [NSImage imageNamed:] using the names NSAscendingSortIndicator (the "^" icon), and NSDescendingSortIndicator (the "v" icon).

NSTableView's encodeWithCoder: method now archives the autosaveName, but only if you are using keyed archiving. NSTableView's initWithCoder: method reads the autosaveName and then sets its columns to those found in user defaults.

In 10.1, the rowsInRect: method returned the range {0,0} whenever the inRect parameter contained a negative y component, even if the height was tall enough to intersect with some rows in the table. This has been fixed.

The following methods are now reflected in the Java API for NSTableView:
void setIndicatorImage(NSImage indicatorImage, NSTableColumn tableColumn);
NSImage indicatorImage(NSTableColumn tableColumn);
void setHighlightedTableColumn(NSTableColumn tableColumn);
NSTableColumn highlightedTableColumn();

In 10.2 and previous releases, NSTableView did not send its action to its target if the user changed the selection with the keyboard (up and down arrow keys). This issue can be easily handled by catching NSTableView's NSTableViewSelectionDidChangeNotification.


The following are a list of bugs in NSTableView that were discovered too late to be fixed.

Drags starting from a NSTableView no longer automatically support the trash as a destination. This applies to 10.2 and later applications. If you need to drag to the trash, you can do this by subclassing NSTableView and including NSDragOperationDelete in your return value from draggingSourceOperationMaskForLocal:. To determine if a drag ended in the trash, override draggedImage:endedAt:operation:. We hope to make this process easier in the future.


The "Show Grid" flag in IB is ignored. If you have not set the flag in IB, you can turn on grid drawing in code as expected. However, If you have set this flag in IB, you will need to do the following in code to get the grid to draw:
    [tableView setDrawsGrid:NO];
[tableView setDrawsGrid:YES];

NSTableView returns NO from needsPanelToBecomeKey. This means by default a user that navigates using the tab key will skip over tables and outline views. To workaround this, you can subclass NSTableView and return YES from needsPanelToBecomeKey.


Consider a table view containing one column of sliders. If the slider is continuous, you will be continuously sent your action message as the slider is tracking. If in response to this action, you ask for the selected, or edited cell, you will not get back the actual cell that is tracking. And because this cell is a temporary copy of your data cell, there is no way to get at the cell and obtain live values. This bug seems to have been around for quite some time. A simple workaround is to supply a custom subclass as your data cell. In this custom class you can override the tracking routines and mark the current tracking cell so that your other code can get at the cell that is tracking.


The following scenario can be problematic for tables that autosave their table columns. Autosaving table columns can be turned on in IB by setting the "Autosave Name" attribute, or in code by using setAutosaveTableColumns:/setAutosaveName:. This is useful if you want to allow users to customize the list of columns or their order.

Consider a table that autosaves columns, that is specified in IB with the columns (by column identifier): @"ColA", @"ColB". When the user runs your application, the present table column identifiers will written out to user defaults. When the user reruns the program, NSTableView will find a list of column identifiers in user defaults, representing the columns to be used in that table. NSTableView then searches itself for existing columns given those identifiers, keeping the columns it finds in the table and effectively removing the others. If you have removed or renamed (the identifier of) a column in IB you may run into problems because, NSTableView will stop it's searching whenever it hits a column that no longer exists. This can cause it to appear that all table columns after the missing column have disappeared. Worse, if the column that disappeared is the first column identifier found in user defaults, then your table will have NO columns (which will cause NSTableView to raise at a later time).

The workaround is fairly simple. If you need to remove a column, you should leave it around in IB, and remove it in code. If you need to rename a column you can apply a similar technique.


NSOutlineView

Any API that expands or collapses an item now considers the possibility that the outline view may be in the middle of editing a cell. If the edited cell is a child of an item that is about to be collapsed, editing will be ended. If expanding or collapsing an item causes a edited cell to move, the field editor will be repositioned and scrolled to visible if necessary.

In all cases editing is ended gracefully, meaning the value will be applied if it is valid.

See the NSTableView section concerning selections for the additional behavior NSOutlineView inherits.

The internal representation of indices in NSOutlineView has been fixed so that the number of children are no longer limited to 32K.

A significant leak has been fixed in NSOutlineView. Expandable items (those returned from data source API) would sometimes be retained but never released by NSOutlineView, resulting in leaks. Your application will get this fix only if it is linked against 10.2 or later. Applications linked against any previous version will maintain the old behavior for compatibility.


NSComboBox

In 10.1, disabled combo boxes returned YES from acceptsFirstResponder. When users clicked on a disabled combo box, this would cause focus to magically shift to the key view following the combo box. NSComboBox now returns NO from acceptsFirstResponder if it is disabled.


NSToolbarItem

If an image contains multiple representations, NSToolbarItem now chooses the most appropriately sized representation when displaying. For instance, if the image contains a representation which is the same size as a menu item image, that representation will be used in the menu form representation. Further if you find that your icon doesn't scale well in NSToolbar's small icon mode, you can add your own small image representation to the image, and it will be used instead of scaling.


NSToolbar

Toolbars now allow users to configure the displayed size. Toolbars that save their configuration to user defaults will also record the users chosen size. The following API has been added to support configurable toolbar sizes:
    typedef enum {
        NSToolbarSizeModeDefault,
        NSToolbarSizeModeRegular,
        NSToolbarSizeModeSmall
    } NSToolbarSizeMode;
    - (void)setSizeMode:(NSToolbarSizeMode)sizeMode;
    - (NSToolbarSizeMode)sizeMode;
Image items will automatically display a regular (32x32) or small sized (24x24) image as appropriate. If your image contains an image representation of the exact size of the current mode, that image will be used. Otherwise, the most appropriate representation will be scaled to the current modes size. Usually you should just supply the regular sized icon and let the toolbar use scaling when displaying the small version. When NSToolbar creates a scaled version it will add the scaled representation to your original image so that it won't have to create it again as users switch between modes or open multiple windows.

View items may require custom code to adjust their appearance based on the size mode. If your item's view implements setControlSize:, the view will be configured by sending it that method. If your view doesn't implement setControlSize:, NSToolbar will check to see if you view is really a control whose cell implements setControlSize:. In this case, your cell will receive the method. Notice this means most standard controls will automatically be configured for you. For example if you item's view is a NSPopUpButton, NSButton, NSTextField, etc... you won't have any work to do. If you need to customize or perform your own configuration, simply provide you item with a view that implements setControlSize:.


Any property set on a toolbar before it is handed to its window is considered to be the "initial" property of the toolbar. That is, if no values for the toolbar are found in user's preferences, then the initial value will be used. In 10.1 setVisible: NO was basically ignored. This has been fixed. Now, if you do a setVisible:NO, and no values are found in user defaults (this is the first time the user is seeing the toolbar), the toolbar will indeed show up initially hidden.


In Mac OS X 10.1, calling setConfigurationFromDictionary: only changed the state the messaged toolbar. Now, the toolbar properly updates other toolbars with that have the same identifier as the messaged toolbar.


In Puma changing a toolbar items label would sometimes cause all other items in the toolbar to disappear until the window was resized. This is fixed .


setConfigurationDictionary: now pays attention to the shown / hidden flag, and will show / hide the toolbar if the flag is different from the current configuration.


NSCell

In 10.1 using NSCell's -setStringValue:/-stringValue could cause a crash if used within nested autorelease pools. This bug is most commonly seen in Cocoa Java because of the use of autorelease pools in the Java bridge. This bug has been fixed now. You should be aware however, that an app that works in 10.2 may be susceptible to this crasher in 10.1.


If you are editing a cell (e.g. NSTextFieldCell) and ask for the cell's stringValue while the user is typing, you may interrupt multikey character input. You should check the edit field to see if is currently in this state via the following:

[[control currentEditor] hasMarkedText];

...and don't fetch the string value if this returns YES. This is not a problem if you use an NSFormatter. The NSFormatter method isPartialStringValid:... will not be called while in this partial character state.


NSMovieView

A call to -[NSMovieView setMovie:] will now call QuickTime PrePrerollMovie and PrerollMovie functions asynchronously. If you specified a streaming URL, this will initiate the connection but not actually begin playing when the preroll completes unless you have already called -[NSMovieView start:].

NSMovieView has been changed to use NSUndoManager for all undo operations. This enables multiple undo/redo. Note that the undo: method in NSMovieView has been removed since this is now handled by NSUndoManager.


NSImage

A change has been made to -[NSImage initByReferencingFile:]. If the image can be cached because the cached size is smaller than the actual expanded size, i.e an image that is more than 72 dpi, then the original data is flushed and the cached image is used. If you resize the image either larger or by less than 50%, the data will loaded in again from the file. If you expect the file to change or be deleted, you should use -[NSImage initWithContentsOfFile:] instead. This behavior only applies to applications built on 10.2 or later.


You can now set the whether the image caches its representation when drawing the image for the first time.
typedef enum {
NSImageCacheDefault,
NSImageCacheAlways,
NSImageCacheBySize,
NSImageCacheNever
} NSImageCacheMode;
-(void)setCacheMode:(NSImageCacheMode)mode;
-(NSImageCacheMode)cacheMode;
NSImageCacheDefault is the current behavior with bitmap and PICT cached by size and PDF cached when drawing to the screen. NSImageCacheAlways will always cache, NSImageCacheBySize will cache if the cached size is smaller than the data size. Use this when you have setDataRetained:YESto dispose of the image storage. NSImageCacheNeverwill try to never cache.

Note that depending on type of NSImageRep and the drawing composite operation and alpha (fraction), the image may still be cached. For example, PDF data can only be rendered using NSCompositeSourceOver with full alpha so NSImage will still need to cache the image in order to render with other composite operations.

Note that this setting is not encoded or decoded from a nib file if you are using the older encoding. It is saved and restored if you are using keyed coding.


NSBitmapImageRep

Support has been added for reading 1, 2, and 4 bits/sample palette based TIFF files. These images are converted to direct 8 bits/sample RGB or RGBA images when reading. Palette based TIFF files with alpha may have previously been drawn incorrectly.

Support has been added to read and write CMYK JPEG images. Additionally, gray scale JPEG image are now kept as single sample instead of converting to RGB.

Support has been added to read and write 16 bit/sample TIFF images.

Checking image files without type info for whether they are TIFF is now a little more strict. In theory this should be harmless; but, if the previous, looser behavior is desired, the preference NSLooseTIFFChecking can be set with value YES.

-[NSBitmapImageRep setProperty:withValue:] now accepts a value of nil which means you can clear out properties such as ColorSync data.


Animated GIFs

Support has been added to NSBitmapImageRep for animated GIFs. If an NSBitmapImageRep is created from a multi-frame animated GIF file or data, then the image rep will have 3 additional properties:
  NSImageFrameCount
NSImageCurrentFrame
NSImageCurrentFrameDuration
You check for an animated GIF by seeing if the property NSImageFrameCount exists. If it does, it will be an integer NSNumber containing the number of frames. NSImageCurrentFrame returns an integer NSNumber that contains the current frame starting with frame 0 and NSImageCurrentFrameDuration returns the duration of that frame as a floating point NSNumber in seconds. To change to a different frame, set the NSImageCurrentFrame property to the one you want and then check the NSImageCurrentFrameDuration property for the new frame's duration.

Note that there is overhead since the original data needs to be kept around so that each frame can be rendered and if you end up caching the image that contains the rep, changing the current frame wil have no effect on the cached image. Also note that rendering is most efficient when advancing frame by frame. Jumping to an arbitrary frame may take longer.

Here's are some methods on NSImage you can add that may simplify access:
@implementation NSImage(AnimatedImageExtension)
- (int)frameCount {
NSBitmapImageRep* imageRep = [[self representations] objectAtIndex:0];
id property = [imageRep valueForProperty:NSImageFrameCount];
return property != nil ? [property intValue] : 0;
}
- (int)currentFrame {
NSBitmapImageRep* imageRep = [[self representations] objectAtIndex:0];
id property = [imageRep valueForProperty:NSImageCurrentFrame];
return property != nil ? [property intValue] : 0;
}
- (void)setCurrentFrame:(int)frame {
NSBitmapImageRep* imageRep = [[self representations] objectAtIndex:0];
[imageRep setProperty:NSImageCurrentFrame withValue: [NSNumber numberWithInt:frame]];
}
- (float)frameDuration {
NSBitmapImageRep* imageRep = [[self representations] objectAtIndex:0];
id property = [imageRep valueForProperty:NSImageCurrentFrameDuration];
return property != nil ? [property floatValue] : 0.0;
}
@end

Incremental Image loading

API has been added to support incremental image loading. Currently, only JPEG images can be loaded this way but GIF and PNG will be added in the future. The API is in two parts. The NSImage API is meant for clients that either don't have their own data source or go can through NSURLHandle. The direct API is used for clients that can provide their own data directly. While simpler, the NSBitmapImageRep API is synchronous.

The following are a set of delegate methods for NSImage that are called as the image is loading. The are used when first drawing NSImages created via initByReferencingFile: and a new method initByReferencingURL:.
typedef enum {
NSImageLoadStatusCompleted,
NSImageLoadStatusCancelled,
NSImageLoadStatusInvalidData,
NSImageLoadStatusUnexpectedEOF,
NSImageLoadStatusReadError
} NSImageLoadStatus;
@interface NSObject(NSImageDelegate)
- (void)image:(NSImage*)image willLoadRepresentation:(NSImageRep*)rep;
- (void)image:(NSImage*)image didLoadRepresentationHeader:(NSImageRep*)rep;
- (void)image:(NSImage*)image didLoadPartOfRepresentation:(NSImageRep*)rep withValidRows:(int)rows;
- (void)image:(NSImage*)image didLoadRepresentation:(NSImageRep*)rep withStatus:(NSImageLoadStatus)status;
@end
The requirement for progressive image loading is that there be a delegate and the delegate implement the last method image:didLoadRepresentation:withStatus: so it can get a notification when the image is fully available. All the other delegate methods are optional.

If the user cancels the download or there is an error, image:didLoadRepresentation:withStatus: will still be called and the image will contain whatever part of the data is valid. If reading the header failed, the NSBitmapImageRep will remain zero sized.

If you draw the image while it is being downloaded, only the valid rows are drawn. The remainder is filled with white. You can use -[NSImage drawInRect:fromRect:operation:fraction] to trim out the picture using the validRows value.

When you first create the NSImage using a URL, it will contain a zero sized NSBitmapImageRep. When you first draw the image or otherwise require the bitmap data, image:willLoadRepresentation: is called and the image download begins. When enough data has been read to determine the size of the image, image:didLoadRepresentationHeader: is called. At this point, the NSBitmapImageRep is valid and has storage for the bitmap but the bitmap is filled with the image's background colour. As the image downloads, the delegate's image:didLoadPartOfRepresentation:withValidRows: method will be called repeatedly to inform the delegate that more of the image is available. Then when the image has been fully decompressed, the method image:didLoadRepresentation: is called.

There are two new NSImage methods. One to mirror initByReferencingFile:. Using this will archive just the URL and not the image data.
- (id)initByReferencingURL:(NSURL*)url;
This method and initByReferencingFile: allow the background download. initWithContentsOfFile: and initWithContentsOfURL: will both do synchronous downloads though initWithContentsOfURL: now supports more than just file URLs

The other method allows the immediate cancellation when downloading the image. This call has no effect if the image isn't loading.
- (void)cancelIncrementalLoad;
The following API allows a client to feed an NSBitmapImageRep data from a streaming source and have the data be decompressed. The API is intended to be minimal since only advanced clients will probably need to use it.
typedef enum {
NSImageRepLoadStatusUnknownType = -1, // not enough data to determine image format. please feed me more data
NSImageRepLoadStatusReadingHeader = -2, // image format known, reading header. not yet valid. more data needed
NSImageRepLoadStatusWillNeedAllData = -3, // can't read incrementally. will wait for complete data to become avail.
NSImageRepLoadStatusInvalidData = -4, // image decompression encountered error.
NSImageRepLoadStatusUnexpectedEOF = -5, // ran out of data before full image was decompressed.
NSImageRepLoadStatusCompleted = -6 // all is well, the full pixelsHigh image is valid.
} NSImageRepLoadStatus;
- (id)initForIncrementalLoad;
- (int)incrementalLoadFromData:(NSData*)data complete:(BOOL)complete;
First, the NSBitmapImageRep is created using -initForIncrementalLoad. This creates a 0 sized, empty, basically invalid NSBitmapImageRep with no buffer. Then the client will repeatedly call -incrementalLoadFromData:complete: with more and more data, finally passing in YES for complete: when the last chunk of data has become available. The data should be the full data, not just the new data since the decompressor may need to backtrack. This call is synchronous and will decompress as much of the image as possible based on the length of the data. The image rep does not retain the data but the data pointer should not change while inside the method.

If not enough data has been sent to determine the format, NSImageRepLoadStatusUnknownType is returned. The client should continue to call with more data.

Once enough data has been read, NSImageRepLoadStatusReadingHeader may be returned indicating that while the type is known, not enough data has been read to determine the size, depth, etc of the image. The client should continue to call with more data. If it turns out that the format does not support incremental loading, then the NSImageRepLoadStatusWillNeedAllData will be returned. Until you call -incrementalLoadFromData:complete: with YES, this status will be returned though you can continue to call it but no decompression will take place. Once you do call it with YES, then the image will be decompressed and one of the final three status messages will be returned.

If the format does support incremental loading, then once enough data has been read, the image is decompressed from the top down a row at a time. The image rep's information will be valid including pixelsHigh, pixelsWide, size, bitsPerSample, etc including the bitmap data. During this time, -incrementalLoadFromData:complete: will return the number of rows that have been decompressed from the top of the image. You can use this information to draw the part of the image that is valid. The rest of the image will be filled with opaque white. Note that if the image is progressive, you may quickly get the full pixelsHigh value but the image will still be loading so do not use this as an indication of how much of the image remains to be decompressed.

If an error occurred while decompressing, NSImageRepLoadStatusInvalidData is returned. If complete: is YES but not enough data was available for decompression, NSImageRepLoadStatusUnexpectedEOF is returned. If enough data has been provided (regardless of the complete: flag), then NSImageRepLoadStatusCompleted is returned. When any of these three status results are returned, the NSBitmapImageRep will have been adjusted so that pixelsHigh and size as well as the bitmap data will only contain the valid pixels.

To cancel decompression, just pass in the existing data or nil and YES for complete:. If data isn't nil, as much of the remaining data will be decompressed. If you pass in nil, then decompression stops immediately, the image size is adjusted and you get back an NSImageRepLoadStatusUnexpectedEOF status.

Calling -incrementalLoadFromData:complete: after any of the three results or on an image that was initialized from any other init call will result in a NSImageRepLoadStatusCompleted result.


Private images removed

The following private images were removed from the open panel nib. If any app used them out of the AppKit framework, these images will no longer be found:
NSSimpleSaveUpArrow.tiff
NSSimpleSaveDownArrow.tiff
NXSmallFloppyEjectIcon.tiff
NXSmallHomeIcon.tiff
NXSmallFloppyIcon.tiff


NSStatusBar

Removing an item via -[NSStatusBar removeItem:] now removes the item immediately from the menu bar. This change should not affect existing applications.

A problem with an application which put up a status bar item and then becomes active when clicking on the status bar item has been fixed.


NSStepper

A problem that caused stepper values to not change if the stepper was set to not autorepeat has been fixed.


Keyboard UI

A problem where the default keyboard loop in a flipped view was upside down has been fixed.


Popup Menus

Popup button menus and their submenus now match the button's font and font size.


NSPopUpButtonCell

In 10.1.x the text in a borderless popup button is positioned 3 pixels too high. This has been fixed for applications that link against 10.2 or later.

This is a note to point out a potential bug that is not fixed in 10.2. If your application leaks any NSPopUpButtonCell instances, use of command keys later on might cause your application to crash in -[NSApplication sendEvent:]. This crash will actually occur with any NSPopUpButtonCell which has an invalid (deallocated or otherwise) controlView (NSPopUpButton).


NSMenu

New class methods have been added to NSMenu to show and hide the menu bar and find out if it's currently visible.
+ (void)setMenuBarVisible:(BOOL)visible;
+ (BOOL)menuBarVisible;

Menu Item Key equivalents

Some menu item key equivalents are reserved by the system for screen and selection grabs. You can set these key equivalents in Interface Builder but they will not be shown when running. The currently reserved key equivalents are Command-Shift-3 (aka Command-#), Command-Shift-4 (aka Command-$) and Command-Control-Shift-3 and Command-Control-Shift-4.

Recommended command key equivalents for Copy/paste ruler and font (style) commands have been changed. These used to be cmd-1, cmd-2, cmd-3, and cmd-4 respectively; because we want to leave these command keys to applications, the new recommended guidelines for these commands are:

cmd-opt-c copy style
cmd-ctrl-c copy ruler

cmd-opt-v paste style
cmd-ctrl-v paste ruler

TextEdit and Mail follow these guidelines, as well as the menu entries in the Interface Builder palette. However, not all applications on the system have been converted.

cmd-opt-H is now the recommended command key equivalent for "Hide Others".


Delegation and Notification

With AppKit classes which provide delegation and notification (such as NSWindow), if you explicitly register for certain notifications which are also used to send delegate messages, and then when you stop being a delegate, you are unregistered for those notifications. It's not clear how this will be addressed in the future, but you should be aware of this potentially unexpected behavior.


NSTextField and NSMatrix obsolete methods

The following 4 methods from NSTextView and NSMatrix are obsolete and have been removed from the headers. They will continue to work but will emit a log message when used. Use the NSView methods setNextKeyView:, nextKeyView, and previousKeyView instead.
- (void)setPreviousText:(id)anObject;
- (void)setNextText:(id)anObject;
- (id)nextText;
- (id)previousText;

NSTextField, NSTextFieldCell

You can now change the text field bezel to be the rounded style. The text field must already have setBezeled:YES set.
typedef enum {
NSTextFieldSquareBezel,
NSTextFieldRoundedBezel
} NSTextFieldBezelStyle;
@interface NSTextField
-(void)setBezelStyle:(NSTextFieldBezelStyle)bezelStyle;
-(NSTextFieldBezelStyle)bezelStyle;
@end
@interface NSTextFieldCell
-(void)setBezelStyle:(NSTextFieldBezelStyle)bezelStyle;
-(NSTextFieldBezelStyle)bezelStyle;
@end

In Mac OS X 10.1, a NSTextFieldCell in a control would draw its focus ring if its control was being edited. For complex controls with multiple text fields this caused the focus ring to be drawn many times, resulting in a dark focus ring without the desired soft edges. This has been fixed. NSTextFieldCell now checks its 'showsFirstResponder' attribute to determine if it should draw the focus ring when the control is being edited. If you notice that your focus rings don't show up anymore, you can call cell's setShowsFirstResponder: with a value of YES.


Dock Menu

In 10.2, an action sent from a custom dock menu has the NSMenuItem as its sender. In 10.1, the sender was always NSApp.


NSApplication

There is now a better distinction made between document-modal sessions and application-modal sessions. This fixes problems where a sheet on an application-modal window would break the application modality. One result of this change is that -[NSApplication modalWindow] will no longer return a sheet window. If you need access to a sheet window, you may be able to use -[NSWindow attachedSheet].

If you need compatibility with 10.1 because you are relying on -[NSApplication modalWindow] to return a sheet, or because you call -[NSApplication endSheet:returnCode:] to terminate application-modal sessions, you can set the user default NSModalCompatibilityWithMacOS10.1 to YES.

-requestUserAttention: will now cause a spoken notification if spoken notifications are enabled. This is in addition to the existing dock animation behavior.


SEL Arguments

Foundation has been inconsistent in its handling of NULL SEL arguments in the past. In 10.2, for applications linked on 10.2 or later, Foundation raises exceptions in all functions and methods (such as NSObjects -respondsToSelector:) that take SEL arguments if the SEL argument is NULL.


NSOpenGL

Four new constants have been added to NSOpenGLPixelFormat:
NSOpenGLPFASampleBuffers      =  55
NSOpenGLPFASamples = 56
NSOpenGLPFAAuxDepthStencil = 57
NSOpenGLPFAVirtualScreenCount = 128
Two new constants have been added to NSOpenGLContextParameter:
NSOpenGLCPSurfaceOrder        = 235
NSOpenGLCPSurfaceOpacity = 236
The following methods allow the context to be shifted between virtual screens.
- (void)setCurrentVirtualScreen:(int)screen;
- (int)currentVirtualScreen;
This new method allows you to create a new texture with identifier target from the contents of an NSView associated with the NSOpenGLContext.
- (void)createTexture:(unsigned long/*GLenum*/)target fromView:(NSView*)view internalFormat:(unsigned long/*GLenum*/)format;

NSBezierPath

Performance note. If you have a bezier path with a lot of intersecting segments, the time to draw the path might be a lot more than the time to draw multiple paths which have less segments each but the same number total. The intersection comparisons and subsequent rasterization are the cause of the slowdown.

If you notice performance issues with NSBezierPaths that have a lot of segments, and you don't care too much about the absolute correctness of the rendering of intersections, you might want to use smaller segments.


NSGraphics function

The function declaration NSCopyBitmapFromGState is removed from NSGraphics.h. The function implementation was removed in the early stage of Mac OS X development.





Notes specific to Mac OS X 10.1

Versioning

NSApplication.h now declares NSAppKitVersionNumber, which can be used to detect different versions of the AppKit framework (to per-build granularity; there are many builds between public releases). There's also a symbolic value for the Mac OS X 10.0 version of the AppKit:
/* The version of the AppKit framework */
APPKIT_EXTERN double NSAppKitVersionNumber;
#define NSAppKitVersionNumber10_0 577
Clients can compare against this to determine whether they are running on 10.0 or on a newer version. Note that some individual headers for other objects and components 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
Although NSAppKitVersionNumber was not declared in the header files in 10.0, it is still available and can be accessed by applications at runtime. If you are compiling on 10.0, you can declare this variable yourself.

In general you should compare against a version number which you know fixes the problem you are checking for, rather than the exact version of the last external release. As an example, although 10.0 through 10.0.4 all have AppKit version 577, a 577.1 might get released to fix some bug in a future 10.0.x. This is just an example, but this has happened with other frameworks updated in the various 10.0.x software updates.


Keyboard UI

10.1 brings the keyboard navigation feature of Cocoa back to life. Users can now use tab, shift-tab, and various control keys (user settable; see Preferences) to navigate between user interface elements. For instance, using the default settings, ctrl-F2 takes focus to the menu bar and ctrl-F5 takes focus to the toolbar. Note that by default, full keyboard navigation is disabled, and users can only tab between text elements and lists. Hitting ctrl-F1 enables full navigation.

As was the case before, for windows which have an initialFirstResponder set, the kit assumes there is a valid keyboard navigation loop and uses the existing loop. If you have windows with an initialFirstResponder in which you have added or deleted UI elements, the navigation might be messed up.

In windows without an initialFirstResponder, the kit will create a keyboard UI loop for you.

We support a way that custom controls can add a keyboard focus ring around text, graphics, and images. For instance, see keyboard focus in toolbars. This function sets a 'style' in the current graphics context in the current locked focus view which affects all rendering until the graphics state is restored.
typedef enum {
NSFocusRingOnly = 0,
NSFocusRingBelow = 1,
NSFocusRingAbove = 2
} NSFocusRingPlacement;
void NSSetFocusRingStyle(NSFocusRingPlacement placement);
The placement indicates how the focus ring will be drawn. Use NSFocusRingAbove to draw over an image, use NSFocusRingBelow to draw the focus ring under text, and use NSFocusRingOnly if you don't have an image or text. For the NSFocusRingOnly case, fill a shape to add the focus ring around the shape.

Note that the focus ring may actually be drawn outside the view but will be clipped to any clipping superview or the window content view.

Because the focus ring may be drawn outside the view, use the following NSView method to invalidate the area around the focus ring.
-(void)setKeyboardFocusRingNeedsDisplayInRect:(NSRect)rect;
Pass in the rectangle of the control or cell and it will be expanded and invalidated.


NSDocument

In 10.1, NSDocument adds the following end-user features: Hidden file extensions, ability to track documents, folders, and volumes which are renamed, and ability to save documents in a way which preserves aliases to the documents and additional document info (such as icon locations). The recents menu also supports tracking of documents. These features and changes are discussed below. Note that most of these features can be supported in non-NSDocument based applications as well with varying degrees of work. TextEdit, which is not NSDocument based, has some (but not all) of these features; you can find its sources in /Developer/Examples/AppKit/TextEdit.


NSDocument now provides support for the concept of hidden file name extensions, which has been introduced in Mac OS X version 10.1. This feature allows file extensions to be hidden on a per-file basis, which provides cross-platform and web compatibility of files while freeing the users from having to deal with and see extensions. For instance, by default, the user-visible display name of RTF files saved by TextEdit do not have the ".rtf" extension.

There is additional API in NSSavePanel, NSFileManager, and NSDocument to support this feature. The NSSavePanel changes are described further below; NSFileManager changes are described in the Foundation release notes.

In NSDocument, two new methods have been added to support this feature:
- (BOOL)fileNameExtensionWasHiddenInLastRunSavePanel;
Returns YES if a save panel has been presented by this document, and the user chose to hide the name extension of the file that was selected in that save panel. Returns NO otherwise.
- (NSDictionary *)fileAttributesToWriteToFile:(NSString *)fullDocumentPath
ofType:(NSString *)documentTypeName
saveOperation:(NSSaveOperationType)saveOperationType;
Returns the file attributes that should be written to the named document file of the specified document type, as part of a particular type of save operation. The set of valid file attributes is a subset of those understood by the NSFileManager class. Invokers of this method should silently ignore invalid attributes. Of particular interest is the NSFileExtensionHidden attribute, which is documented in the Foundation release notes.

In addition, the behavior of one NSDocument method has changed to support hidden file extensions: -[NSDocument displayName] now returns a displayable document name that takes into account whether or not the document file's name extension should be hidden.

In version 10.1, the dictionary returned by the default implementation of this method will contain an NSFileExtensionHidden entry when that is appropriate. Your subclass of NSDocument can override this method to control the attributes that are set during a save operation. An override of this method should return a copy of the dictionary returned by its superclass' version of this method, with appropriate alterations.

An override of the -writeWithBackupToFile:ofType:saveOperation: method should invoke this method and set the returned attributes on the written document file, possibly using the -[NSFileManager changeFileAttributes:atPath:] method.

Implementers of overrides of this method should not assume that:
• The file pointed to by fullDocumentPath at the moment the method is invoked, if there is one, is related to the document itself. It may be an unrelated file that is about to be overwritten.
• -fileName or -fileType will return anything useful at the moment.


NSDocument now implements document saving in a way that preserves, when possible, various attributes of each document, including:
• Creation date.
• Permissions/privileges.
• The location of the document's icon in its parent folder's Icon View Finder window.
• The value of the document's Show Extension setting.

Care is also taken to save documents in a way that does not break any user-created aliases that may point to documents.

As a result, some methods in any subclass of NSDocument may now be invoked with parameters that are different from what would have been used in the past. For example, it is now more important than ever that overrides of -writeToFile:ofType:originalFile:saveOperation: and -writeToFile:ofType: make no assumptions about the file paths that are passed as parameters, including:
• The location to which the file is being written. Likely as not the file is being written to a hidden temporary directory.
• The name of the file being written. It is possible that the file name will have no obvious relation to the document name.
• The relation of any file path being passed, including originalFile, to the return value of [self fileName].

For backwards binary compatibility, NSDocument will exhibit nearly the exact same behavior as it did in Mac OS 10.0, when running in programs that were linked against the Mac OS 10.0 version of the AppKit or Cocoa framework.


Open documents now have the ability to track the files from which they were opened (or to which they were most recently saved) so that they withstand the sort of moving and renaming of documents, folders, and volumes that the user can do with the Finder. This feature manifests itself in the user interface in two ways:
• If the user uses the Finder to move or rename an open document, a containing folder, or the volume, the document window's title and document location menu (as seen when you command-click on the window title) will be updated automatically when the application is reactivated.
• When the users attempts to save a document after any of the above operations have been performed, an appropriate alert panel may be presented to let the user select an appropriate action.

As a result of this addition, instances of NSDocument will be sent several messages, -setFileName: in particular, more frequently than they have been in the past.


The -fileAttributesToWriteToFile:ofType:saveOperation: method mentioned above can be overridden to specify that a creator code and/or file type code should be written to a file as it is being saved. See the Foundation release notes for descriptions of the new NSFileHFSCreatorCode and NSFileHFSTypeCode file attributes. NSDocument's implementation of -fileAttributesToWriteToFile:ofType:saveOperation: returns zeroed-out creator and file type codes, effectively excluding creator code and file type code from the attribute preservation described above.

-[NSDocument runModalPageLayoutWithPrintInfo:delegate:didRunSelector:contextInfo:] will now present the page layout panel application-modally if there is no document window to which it can be presented document-modally.


There was a bug in which the value of the originalFile parameter was incorrect during invocations of -writeToFile:ofType:originalFile:saveOperation: that took place during Save As operations. It was always either nil or a path to a file being overwritten. Now it is the path to the document's current location on disk, or nil if the document has never been saved before.


NSDocumentController

At the time of the release of Mac OS X, version 10.0, the Mac OS X Cocoa AppKit Release Notes claimed that:

"NSDocumentController's -fileExtensionsFromType: now returns an array of file type strings that may contain encoded HFS file types as well as file name extensions. -runModalOpenPanel:forTypes: and -typeFromFileExtension: behave as they always have, but will now accept file type strings that contain encoded HFS file types as well as file name extensions. -openDocumentWithContentsOfFile:display: and -openDocumentWithContentsOfURL:display: now take the HFS file type of files into consideration when deciding what subclass of NSDocument should be instantiated."

That was not true, but it is true now. (The rest of the release note dealing with HFS file types was accurate.) None of the NSDocumentController methods named in that release note, except for -runModalOpenPanel:forTypes:, handled HFS file types correctly. Now, -fileExtensionsFromType:, -runModalOpenPanel:forTypes:, -typeFromFileExtension:, -openDocumentWithContentsOfFile:display:, and -openDocumentWithContentsOfURL:display: all handle HFS file types correctly.


NSDocumentController's implementation of the Open Recent menu now attempts to withstand the sort of moving and renaming of documents, folders, and volumes that the user can do with the Finder. If the user does any such operation involving the document, selection of the corresponding Open Recents menu item still results in the opening of the document.

Documents that cannot be located no longer appear in the Open Recent menu at all.

The name extensions of files shown in the Open Recent menu will also be hidden or shown as appropriate.


-[NSDocumentController reviewUnsavedDocumentsWithAlertTitle:cancellable:delegate:didReviewAllSelector:contextInfo:] now completely ignores the passed-in alert title string.


NSWindowController

There was a bug in NSWindowController in which the document name returned by an override of -[NSDocument displayName] would not be used for document window titles. That bug has been fixed.


NSSavePanel

In order to support the hidden file extension feature discussed above, a checkbox has been added to the save panel that allows the user to hide or show the extension. Existing non-NSDocument based applications will need to be modified to set the flag; by default, the checkbox is not visible. (In most cases this feature is automatically supported for NSDocument based apps.)

The new API consists of 3 methods in NSSavePanel.h:
- (void)setCanSelectHiddenExtension:(BOOL)flag;
- (BOOL)isExtensionHidden;
- (void)setExtensionHidden:(BOOL)flag;
setCanSelectHiddenExtension: shows the checkbox in the save panel. It needs to be called before runModal:, etc.

setExtensionHidden: allows the app to set the checkbox. should will rarely be used since the state is saved on a per app basis.

isExtensionHidden returns YES if the checkbox is visible and checked. This flag can be used to set the hidden extension bit in the saved files via NSFileManager API.


NSProgressIndicator

The height of the small progress indicator as generated was Interface Builder in nib files was wrong. It should be 12 instead of 10. Please open any nib files containing small progress indicators, switch the effected controls to large and back to small again, and save.


NSPDFImageRep

-[NSImage draw...] methods, when invoked on a PDF image during printing, very often created no output. This was a bug, and has been fixed.


NSPrintOperation

The NSPrintPreviewJob and NSPrintSaveJob job dispositions were not supported in Mac OS 10.0.x. They are in Mac OS 10.1.

The attribute that is accessed using -setShowPanels: and -showPanels now controls whether or not a printing progress panel is presented by -runOperation or -runOperationModalForWindow:delegate:didRunSelector:contextInfo:.


Scripting

The default value of of NSApplication's "version" scripting attribute is now the CFBundleShortVersionString entry in the application's Info property list, instead of the number zero. This value can still be overridden by the application delegate object.


NSButton

-[NSButton setKeyEquivalentModifierMask] now supports NSCommandKeyMask as an argument. When a commandKey modifier is present in a keyDown event, NSApplication now looks for a command-key equivalent in the key window before sending the event to the menu. A command-key equivalent in the key window will therefore have precedence over the same command-key equivalent in a menu. It is preferable to avoid such collisions, however.


Command-d key equivalent

NSRunAlertPanel and NSBeginAlertSheet now provide a command-d key equivalent for the "Don't save" button in the panel, if one is found. The button titles are searched for the localized value for "Don't save". If a match is found, that button is assigned a command-d key equivalent, provided it is not already the default button. (It does not work to assign both command-d and return as key equivalents for the same button, so return takes priority).

If you create a modal panel using -[NSApplication runModalForWindow:] or -[NSApplication beginSheet:modalForWindow:modalDelegate:didEndSelector:contextInfo:], you can assign the key equivalent yourself, using -[NSButton setKeyEquivalent] and -[NSButton setKeyEquivalentModifierMask:].


NSWindow

In 10.1, on multiple monitor machines, windows whose locations are being restored from saved frames will be shown on the screen where they were before being closed, assuming that there is such a screen in the current display configuration. If there is no screen approximating the location of the screen saved with the window frame, the window will be placed on the screen containing the menu bar.

-isSheet has been added to indicate when a window is a "sheet", or document modal panel. There is also a method to ask for the sheet attached to a window, -attachedSheet. If such a sheet exists, this indicates that the window is in a document modal state. If the window does not have an attached sheet, this method returns nil.

A notification is sent before a sheet is presented on a window, NSWindowWillBeginSheetNotification, and after it is dismissed, NSWindowDidEndSheetNotification.
- (BOOL)isSheet;
- (NSWindow *)attachedSheet;
A window delegate should implement the following to receive the sheet notifications:
- (void)windowWillBeginSheet:(NSNotification *)notification;
- (void)windowDidEndSheet:(NSNotification *)notification;
There was a bug in 10.0 where calling setAspectRatio: on a window would cause it to resize to the zero frame the moment you tried to resize it. As of Puma5G21 -setAspectRatio: now enforces the aspect ratio correctly for resize operations.

In 10.1, the string passed into -[NSWindow setTitle:] will be copied rather than retained by the window. This provides the correct behavior for titles set using mutable strings. However, if you depend on NSWindow to retain this string in order for your application to later modify it, you will need to retain the string yourself. Also note that modifications made after the string is passed into setTitle: will not be reflected in the title of the window.

There are known issues with window positioning and the dock. New windows frequently do not respect the dock position - especially if the dock is on the left side of the screen rather than the bottom. This can result in windows being partially obscured by the dock.

There is also a less common problem where collapsing the save panel can cause the document window to move to an unexpected location. This is a problem that is caused by failure to initialize the window position properly in some cases. You can workaround this problem in your application by positioning the document window with -[NSWindow setFrame:display:] rather than passing the positioned frame into -[NSWindow initWithContentRect:styleMask:backing:defer:].


NSScreen

We now have support for dynamic screen reconfiguration. This will allow certain models of PowerBooks to discover displays added or removed on waking from sleep. When a display is added or removed, the contents of +[NSScreen screens] will change, so applications should not cache the screens array.


NSEvent

Event types have been added for "other" mouse events. These events can be generated by an input device with more than two buttons:
NSOtherMouseDown      = 25,
NSOtherMouseUp = 26,
NSOtherMouseDragged = 27
The corresponding event masks are also defined:
NSOtherMouseDownMask      = 1 << NSOtherMouseDown,
NSOtherMouseUpMask = 1 << NSOtherMouseUp,
NSOtherMouseDraggedMask = 1 << NSOtherMouseDragged
A method has been added to get the buttonNumber for the mouse button that generated the OtherMouse event. The -buttonNumber method is intended for use with the OtherMouse events, but will return constant values for LeftMouse and RightMouse events as well:
- (int)buttonNumber;
NSResponder methods have been added for handling these events. An NSResponder subclass can implement these methods to get called when an OtherMouse event is received:
- (void)otherMouseDown:(NSEvent *)theEvent;
- (void)otherMouseUp:(NSEvent *)theEvent;
- (void)otherMouseDragged:(NSEvent *)theEvent;
-[NSEvent deltaX] and -[NSEvent deltaY] now return mouse delta for mouse move and mouse dragged events.


-[NSEvent locationInWindow] may now return NSPoints with non-integral coordinates to represent sub-pixel precision generated by some input devices, for instance tablets. -[NSDraggingInfo draggingLocation] and -[NSDraggingInfo draggedImageLocation] may also return non-integral locations. Applications should not assume that these locations will be on pixel boundaries.


NSApplication

If your application uses NSStatusItems and implements - (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag, there is a known problem where the hasVisibleWindows flag will always be YES even if there are no visible windows aside from the NSStatusItems.

If your application uses NSStatusItems and needs to accurately distinguish between having visible windows and not, you should add your own check in -applicationShouldHandleReopen:hasVisibleWindows:. For example, it might make sense to ask if -[NSApp mainWindow] is nil as a way to check for visible document windows.


NSApplication Dock Interaction

NSApplication has added support for applications to specify the contents of the application dock menu. This allows an application to add menu items below the list of windows in the dock menu.

An application can either specify an NSMenu in a nib, or return an NSMenu from a delegate method.

To specify an NSMenu in a nib, add the nib name to the info.plist, using the key AppleDockMenu. The nib name should be specified without an extension. There will be an IB outlet from NSApplication named dockMenu, which should be connected to the NSMenu in the nib. This menu should be in its own nib file so that it can be loaded lazily when the dockMenu is requested, rather than at launch time.

There is also an application delegate method to allow a delegate to specify the menu dynamically. If the delegate returns non-nil for this menu, it takes precedence over the dockMenu in the nib. Because this method is invoked whenever the dockMenu is to be shown, efficiency is important. The delegate should keep its own internal representation of the dock menu up to date rather than updating when this method is invoked.
- (NSMenu *)applicationDockMenu:(NSApplication *)sender;
The target and action for each menu item is passed to the dock. On selection of the menu item, the dock messages the application, which invokes [NSApp sendAction:selector to:target from:nil].

The current implementation does not yet support adding an image to a menuItem or changing the menu title based on modifier keys, which are both features desired in the dockMenu.


We now have support for "Dock Notifications", basically user notifications to allow an application that is not frontmost to request user attention. The dock supplies a new kind of app tile animation to indicate this notification.

To start a notification, an application would call:
- (int)requestUserAttention:(NSRequestUserAttentionType)requestType
requestType is either NSInformationalRequest or NSCriticalRequest. We bounce the dock icon for one second (usually one bounce) for an informational request, and until the app becomes active for a critical request. Activating the app cancels the user notification request. Making this call in an app that is already active has no effect.

The return value is a request tag that can be passed to:
- (void)cancelUserAttentionRequest:(int)request
cancelUserAttentionRequest: allows an application to cancel a previous request. request is the return value from a previous call to requestUserAttention:. In the common case, a request will be cancelled automatically by user activation of the application. This method provides the less frequently needed facility for cancelling a request without explicit activation.

The additions to NSApplication.h are:
enum {
NSInformationalRequest = 0,
NSCriticalRequest = 1
} NSRequestUserAttentionType;
- (int)requestUserAttention:(NSRequestUserAttentionType)requestType
- (void)cancelUserAttentionRequest:(int)request
If an inactive app presents a modal panel, we call -[NSApp requestUserAttention:NSCriticalRequest] automatically for the application. The modal panel is no longer brought to the front (using NSModalPanelWindowLevel) for an inactive application.


Standard About Panel

The standard about panel now supports links in the Credits area; clicking on a link causes it to be opened in the default application prepared to handle the link. You can specify the links in the attributed string you provide (as the value of the "Credits" key in the dictionary), or in a Credits.html file, which will be looked for before Credits.rtf. Note that Credits.html is not looked for in 10.0, so if you do provide one, you might also want to provide a Credits.rtf file. There is also support now for Credits.rtfd.


Alerts

In 10.1 the alert panel presented by NSRunCriticalAlertPanel and the sheet presented by NSBeginCriticalAlertSheet will badge the application icon with a caution icon. These functions should be used only as specified by the Human Interface Guidelines.


NSFileWrapper

Bug Fixes
- Improved error handling. Under some circumstances errors were being ignored during initialization (rather than returning nil) and the resulting file wrapper could cause a segfault when it was used.
- Broken, absolute links are now copied into the file wrapper instead of being treated as an error.

Known Problems
- File wrappers ignore resource forks.
- File wrappers resolve relative links - i.e. they copy the links destination rather than reproducing the link. This is especially problematic if the link is broken or if following the link results in a cycle.


NSWorkspace

A bug has been fixed in which NSWorkspace did not deliver its NSWorkspaceDidUnmountNotification if a volume was forcibly and immediately made unavailable, for example by simply unplugging a firewire drive. In this case the NSWorkspaceDidUnmountNotification will now be delivered, but the NSWorkspaceWillUnmountNotification still will not be, because there is no chance to deliver it before the volume is unmounted.


Text

The NSAttributedString methods
- (id)initWithPath:(NSString *)path documentAttributes:(NSDictionary **)dict;
- (id)initWithURL:(NSURL *)url documentAttributes:(NSDictionary **)dict;
and the NSMutableAttributedString method
- (BOOL)readFromURL:(NSURL *)url options:(NSDictionary *)options documentAttributes:(NSDictionary **)dict;
can now use filter services to convert the specified file into a format recognized by the Cocoa text system (plain text, rtf, rtfd, or html). In addition to the existing pasteboard types for plain text, rtf, and rtfd, there is now an NSHTMLPasteboardType that can be used for this purpose, and can also be read (but not written) by NSTextView. In addition to these pasteboard types, text filter services can also convert to typed filenames pasteboard types (again, of the types txt, rtf, rtfd, or html). To support the use of filter services, a @"Converted" key is supplied in the returned document attributes to indicate whether the file was converted by a filter service or not (if it was, then a text editor, for example, would probably not wish to write the file back in the same location). In addition, the following methods
+ (NSArray *)textUnfilteredFileTypes;
+ (NSArray *)textUnfilteredPasteboardTypes;
+ (NSArray *)textFileTypes;
+ (NSArray *)textPasteboardTypes;
are available to determine what types can be loaded as text.


TextView will now attempt to open links if there is no delegate or the delegate method for handling links returns NO. Note that the textview might not be able to open some links as it does not have the proper base URL in many cases.


We now handle the following new key in the documentAttributes dictionary when reading/writing files:

@"ReadOnly": NSNumber containing an int; 0 or less: editable, 1 or more: readonly. If not present, implies a value of 0, that is, editable. Note that readonly state has nothing to do with file system protection; it simply indicates how the document should be presented to the user. TextEdit has a new menu item to take advantage of this setting.


There are now first responder action methods for speaking user-visible text in Cocoa,
- (void)startSpeaking:(id)sender;
- (void)stopSpeaking:(id)sender;
implemented on NSTextView, and which can be implemented as appropriate on other responders. The NSTextView default context menu contains items to invoke these methods.


The NSTextView method
- (BOOL)shouldChangeTextInRange:(NSRange)affectedCharRange
replacementString:(NSString *)replacementString;
will now automatically return NO if the textview is not editable. This prevents some instances in which a textview could be changed by user actions even though it had been set to be non-editable. The general rule followed here is that NSTextView, as the view layer in the text system's model-view-controller structure, enforces any restrictions on interaction with the user, and is appropriately used for actions that are directly occasioned by user actions. Programmatic changes to the text which should not need those restrictions should be made at the model layer, i.e., in NSTextStorage.

One thing to keep in mind in this connection is that actions recorded on the undo stack by the text system take place at the model layer. Therefore, if a textview at any point changes from being editable to not being editable, any actions related to it still on the undo stack will still be able to be undone. If the change in editability is intended to be irreversible (for example, if it corresponds to a change being irrevocably committed to a database) then steps should be taken to remove any such undo actions at the time of the change. On the other hand, if the change in editability is reversible, then that change should itself be made undoable, so that it would be undone in the process of passing down the undo stack before reaching any items that would alter the text.


NSLayoutManager now provides a threshold for text antialiasing. It looks at default value set by Preferences. If the font size is smaller than or equal to this threshold size, the text is rendered aliased by NSLayoutManager. You can change the threshold value from System Preferences application's General pane.


NSDrawer

Several problems in NSDrawer have now been fixed. First, there was a problem that caused drawers with a maximum content size not to be able to be manually resized to that maximum size. That has been fixed. Second, there was a problem with setContentSize:, which was not interpreting its argument correctly. That has been fixed, but applications that linked against previous versions of Cocoa or AppKit will continue to use the old behavior. Third, the delegate method drawerWillResizeContents:toSize: was not being sent; now it is. For comparison with NSAppKitVersionNumber, the version number in which these changes occurred was 592.


NSColorPanel

NSColorPanel can now toggle between visible / hidden.

Any menu item that matches the default "Show Colors" menu item in IB will exhibit new behaviour. Instead of simply showing the color panel, the menu item will now toggle the visibility of the color panel. If the color panel is hidden already, it will order it front. If the color panel is already ordered front, selecting the menu item will hide the color panel.

Your "Show Colors" menu item will only exhibit this new behavior if it's target is FirstResponder and it's action is orderFrontColorPanel:. Further if your menu item's title matches the default in IB (localized comparison), "Show Colors", then menu validation will title your menu appropriately to indicate whether selecting the menu item will hide or show the color panel. If your title is not toggling appropriately, it either because the menu items title doesn't match the default from IB, or you have a custom subclass of NSApplication that overrides validateMenuItem: and does not call [super validateMenuItem:].


NSFontPanel

NSFontPanel can now toggle between visible / hidden.

Any menu item that matches the default "Show Fonts" menu item in IB will exhibit new behaviour. Instead of simply showing the font panel, the menu item will now toggle the visibility of the font panel. If the font panel is hidden already, it will order it front. If the font panel is already ordered front, selecting the menu item will hide the font panel.

Your "Show Fonts" menu item will only exhibit this new behavior if it's target is the shared NSFontManager object (The "A", or "Font Manager" icon in your IB document) and it's action is orderFrontFontPanel:. Further if your menu item's title matches the default in IB (localized comparison), "Show Fonts", then menu validation will title your menu appropriately to indicate whether selecting the menu item will hide or show the font panel. If your title is not toggling appropriately, it probably because the menu items title doesn't match the default from IB.


NSTabView

NSTabView's controlSize method was incorrectly declared as: -(NSControlTint)controlSize. It is now correctly declared as: -(NSControlSize)controlSize. This change will not break compatability as NSControlTint and NSControlSize are both the same size.


Users can now navigate a tab view and it's items using the keyboard. Using the tab key, users can place keyboard focus on an NSTabView and switch between tab items by pressing the arrow keys. With focus on the tab view itself, hitting tab will take the user to the selected item's initialFirstResponder. Continuing to tab will take users through the keyloop you have defined, eventually leading a user out of the NSTabView (usually the view connected as the tab view's nextKeyView in IB).

There are a couple of details that should be mentioned:

- The initially provided nextKeyView of a NSTabView is remembered as the "original next key view".

- Each NSTabViewItem should provide an initialFirstResponder and a valid keyboard loop. If you do not prvide one, it is assumed you have in fact not provided any keyboard loop. Therefore, a keyboard loop will automatically be created.

- The last key view in a NSTabViewItem's loop will be given the "original next key view" as its next key view. If there is no original next key view, the last key view's will be wired to the tab view itself.

- The keyboard loop you provide should not contain cycles. If found, the cycle may be broken, so that tabbing past the last key view will take users out of the tab view. The location the cycle is broken will be considered the item's last key view.

- The keyboard loop you define should not lead outside of a NSTabViewItems view. If this is detected, the link causing keyboard focus to leave the view may be broken. This location will be considered the item's last key view.

Summary: Each NSTabView should have an original next key view (usually provided in IB). Each NSTabView items should be given an initialFirstResponder, and a valid keyboard loop. Typically using the tab key will take user to the tab, through the selected items keyboard loop, and then out the other side.


NSCell

NSCell has support for drawing the proper highlight color in non-key windows. This method return the color to use when drawing a selection highlight:
- (NSColor *)highlightColorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView;
In the past developers typically assumed that the color use was [NSColor selectedControlColor]. However, now some controls want to draw with different selection highlight colors depending on things such as key state of the controlView in which the cell is displayed. In order to be sure you are using the correct selection highlight color, you should search your existing code for places that assume the use of [NSColor selectedControlColor].


NSBrowser

The setPath: contains a bug fix, which causes a slight, yet desirable change in behavior. The method should, and now does, return YES whenever path is valid, and NO otherwise (previously it return NO if a leaf was matched).

While parsing the string, NSBrowser tries to locate matching entries in its columns. If an exact match is found, the match will be selected and the next entry will be processed. The algorithm proceeds until finished with the string, or until an entry can't be matched.


NSTableView

Table views and outline views now allow you to drag entries without the application being active. This change only affects clients using the row/item based dragging APIs. Dragging from such a table now acts more like NSTextViews implementation of dragging. If you app is not active, and the users can now drag from your table. If they simply click, the selection will not be affected. In this situation you app will become active, but the selection will not change.

To facilitate this feature, NSTableView now implements:
- (void)shouldDelayWindowOrderingForEvent:(NSEvent *)theEvent;
- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent;

NSPDFImageRep

The size of the image rep is now set from the PDF's crop box instead of the media box. If they didn't match, you may find the image appears larger.


NSMovie

-[NSMovie initWithURL:byReference:] will now accept and play network based URLs (http:, rtsp:, etc.). When starting to play the movie, the NSMovieView will not is not resized. You will need to register with the movieController to receive a callback when the size changes dynamically and update the NSMovieView to match.


NSView

NSView now has live resizing API:
- (void)viewWillStartLiveResize
- (void)viewDidEndLiveResize
These methods will be sent to a view before live resize starts, and after it ends. In the simple case, a view will be sent viewWillStartLiveResize before the first resize operation on the containing window, and viewDidEndLiveResize after the last resize operation. A view that is repeatedly added and removed from a window during live resize will receive only one viewDidStartLiveResize message (on the first time it is added to the window) and one viewDidEndLiveResize message (when the window has completed the live resize operation). This allows a superview such as NSBrowser to add and remove its NSMatrix subviews during live resize without NSMatrix receiving multiple calls to these methods.

A view might allocate data structures to cache drawing information in viewWillStartLiveResize, and should clean up these data structures in viewDidEndLiveResize. In addition, a view that does optimized drawing during live resize might want to do full drawing after viewDidEndLiveResize, although a view should not assume that it has a drawing context in viewDidEndLiveResize (since it may have been removed from the window during live resize). A view that wants to redraw itself after live resize should call [self setNeedsDisplay:YES] in viewDidEndLiveResize.

A view subclass should call super from these methods.
- (BOOL)inLiveResize
This is a convenience method, expected to be called from -drawRect: to make decisions about optimized drawing.

NSView's unlockFocus method now raises NSInvalidArgumentException exception if the method is invoked on a wrong view.

Also see elsewhere in this document for discussion of the new method setKeyboardFocusRingNeedsDisplayInRect:.


NSOpenGLPixelFormat

initWithAttributes: will now return nil if the format attributes provided aren't supported or conflict. It previously returned a valid format but created with no attributes which mean no depth buffer.

Please note that the NSOpenGLPixelFormat methods -initWithData:, -setAttribute:, and -attributes are deprecated and will be removed in a future release. It is also not recommended that you archive an NSOpenGLPixelFormat.

There are two new NSOpenGLPixelFormatAttribute enum values which are not listed in the headers but available in Mac OS X 10.1:
NSOpenGLPFASampleBuffers = 55
NSOpenGLPFASamples = 56
These are for GL_ARB_multisample support.


NSFont

Although NSFonts are long-living instances which never go away, they should be retained and released just like any other autoreleased return --- for instance, NSColors. If this is done properly, at some point we will be able to make NSFonts truly autoreleased, allowing them to go away when no longer needed.

-[NSFont descender] method used to return the value with the line gap (leading) added for Japanese Hiragino font family in 10.0. In 10.1 the method returns the correct descender value specified in the font. In order to get the default line height that should include the ascender, descender, and leading, use -[NSFont defaultLineHeightForFont] method.


NSColor

NSColor now has a secondarySelectedControlColor method, providing somewhat dimmed color used to display selections in tableview, browser, etc when inactive. In addition, NSColor's disabledControlTextColor method now correctly archives itself. These colors can be unarchived on all systems, back to 10.0.


NSStatusBar

NSStatusBar allows you to place persistent UI elements in the menu bar. There are a few important things to note.

1. Just like with Apple's status bar items, you should allow provide a user preference for any status bar items you intend to display. This way, even if the user installs many applications with status bar items, they can choose the ones they want to see.

2. Space in the menu bar is a precious commodity. Depending on the size of the menu of the active application and the user's display size, your status bar items might get clipped and not get displayed. In addition, other factors might cause status bar items to stop displaying permanently in a future release. Because of these reasons, don't count on the status bar item as the sole way to inform the user of status. This is reasonable, considering #1 above.

3. The location and size of status bar items might change in a future release. Don't make too many assumptions about the location and size of these items.



NSScroller

NSScrollArrowPosition enum has been changed in order to accomodate the additional style introduced in 10.1 (arrows together). Note that NSScrollerArrowsMaxEnd and NSScrollerArrowsMinEnd values are now deprecated. You can only access NSScrollerArrowsNone or NSScrollerArrowsDefaultSetting. NSScrollerArrowsDefaultSetting gets the configuration from user's preferences.


NSSplitView

NSSplitView now tiles its subviews and splitters correctly. -[NSSplitView drawDividerInRect:] used to receive the height that is 2 pixel higher than the value returned from -dividerThickness.


String Drawing

In releases prior to 10.1, there were cases in which -[NSString drawAtPoint:withAttributes:] and -[NSAttributedString drawAtPoint:] would shift the point at which the string was drawn, or clip the string incorrectly, if the point was specified so as to place the string partly or wholly outside of the bounds of the current focused view. This has been fixed in 10.1.

One caution is that the behavior of NSRightTextAlignment and NSCenterTextAlignment paragraph styles with the drawAtPoint: calls is not well-defined. If you wish to use these alignment styles with string drawing, we strongly recommend the use of the drawInRect: string drawing calls rather than the drawAtPoint: variants. For backward compatibility, the string drawing implementation in 10.1 attempts to mimic the behavior of previous releases when right or center justification is used with drawAtPoint: calls, but this behavior is not guaranteed and may change from release to release.



Notes specific to Mac OS X 10.0


NSToolbar

NSToolbar and NSToolbarItem are new classes which provide a mechanism for creating standard toolbars you can attach to titled windows.

To create a NSToolbar you will need to provide a delegate that can provide NSToolbarItems on demand, and answer a number of important questions. First, a toolbar's delegate provides, by identifier, the list of default toolbar items. This list is used when reverting to default, and constructing the initial toolbar. Next, the delegate provides the list of allowed item identifiers. The allowed item list is used to construct the customization palette, if the toolbar is customizable. Finally, the delegate must implement the method that returns NSToolbarItems for a given item identifier.

When you create an NSToolbar you give it an identifier. NSToolbar assumes all toolbars with the same identifier are the same, and automatically synchronizes changes. For instance, consider writing a Mail application. Your applications compose window toolbar would have the same identifier string. So, when you re-order items in one toolbar, the changes automatically propagate to any other compose windows currently open.

Most toolbars will contain simple clickable items. The simplest NSToolbarItem is defined by its icon, label, palette label (used in the customize sheet), target, action, tooltip and other attributes. Most toolbars can sufficiently be represented using these simple button-like items. However, if you need something custom in your toolbar, it is possible. Custom views are provided by calling setView: on NSToolbarItem. For instance, if you want your development tool to have a pop for selecting build styles, you can provide your toolbar item with a NSPopupButton.

There are a couple of standard item identifiers that NSToolbar knows about. NSToolbarSeparatorItemIdentifier is the identifier for the standard vertical line separator. NSToolbarSpaceItemIdentifier represents a fixed width space that can be dragged into the toolbar. NSFlexibleSeparatorItemIdentifier represents a variable width space. There is also NSToolbarShowColorsItemIdentifier, NSToolbarShowFontsItemIdentifier, NSToolbarPrintItemIdentifier, and NSToolbarCustomizeToolbarItemIdentifier. These items are only accessible by identifier.

If you need to change the action sent by a standard item, you can do this in toolbarWillAddItem:.

A couple of methods have been added to NSWindow to help support NSToolbar. NSWindow now lets you add a toolbar, show/hide the current toolbar, and run the customization palette. If you add menu items in your application and hook them up to toggleToolbarShown:, and runToolbarCustomizationPalette: NSWindow will take care of validation. In particular, the menu item with toggleToolbarShown: as its action will properly title the menu item dependent on the current state of the toolbar.
/* Set and Get a window's toolbar. */
- (void)setToolbar:(NSToolbar*)toolbar;
- (NSToolbar *)toolbar;
/* Targets / action methods. */
- (void)toggleToolbarShown:(id)sender;
- (void)runToolbarCustomizationPalette:(id)sender;
NSWindow shows the toolbar by growing the size of the window, thus keeping the content area the same size. If the window is the same size as the screen with the toolbar hidden, showing will cause the content to shrink. That way, the resize box doesn't run off the screen.

An application's "Hide/Show Toolbar" and "Customize Toolbar..." menu items (in that order) should be placed in the same menu. In almost all situations, the menu items make the most sense under the "Window" menu. Please refer to the Aqua Interface Guidelines for more information on where to place these menu items.

Known bugs & Limitations:

- Dragging into toolbar will sometime cause clipped items to "slide" into view temporarily.
- If a window's contents are not resizable, showing the toolbar can sometimes run the bottom of the window off screen.
- There is currently no support for declaring items as non-removable(?). All items are removable.
- There is no support drag and drop on toolbar items, except that you can supply your own custom views to do it.
- There is currently no way to specify a specific customization sheet layout, for instance you can't set the size of the sheet
- There is currently no pressed state for items when in Text Only mode.
- Toolbar items look inactive during show/hide animation.
- If the delegate returns nil for a particular item, the toolbar shows strange garbage instead of just dropping the item from the toolbar.


NSStepper, NSStepperCell

This is a new control subclass that implements what in Carbon are called 'little arrows'. This is a two part control that increments and decrements a value. This is a common control for date and time entry. NSStepper is a subclass of NSControl, NSStepperCell is a subclass of NSActionCell. They both implement the following additional API:
- (double)minValue;
- (void)setMinValue:(double)minValue;
- (double)maxValue;
- (void)setMaxValue:(double)maxValue;
- (double)increment;
- (void)setIncrement:(double)increment;
- (BOOL)valueWraps;
- (void)setValueWraps:(BOOL)valueWraps;
- (BOOL)autorepeat;
- (void)setAutorepeat:(BOOL)autorepeat;
You can set and get the minimum, maximum, and increment values. If valueWraps is set to YES, then when incrementing or decrementing, the value will wrap around the minimum or maximum. If it doesn't wrap, then it will be pinned. If autorepeat is YES, then the first mouse down will do one increment and after a delay of 0.5 seconds, it will increment at the rate of 10 times per second. If autorepeat is NO, then it will do one increment on a mouse up in the control. Defaults for value, min, max, and increment are 0, 0, 59, and 1. Both valueWraps and autorepeat are set to YES.


NSWindow

The proxy icon in the titlebar is now a small version of the file's icon, rather than a generic document icon. The file name in the titlebar no longer contains the path to the file. The path to the file may be shown by command-clicking on the document proxy. Selecting an item from this path will open a viewer window in the finder, with that item selected.

NSWindows now support option-clicking in th titlebar buttons. If the close, minimize, or zoom button is option-clicked, the operation takes place on all eligible windows owned by the application. For a window to be eligible, it must be visible and must support the operation.

The rectangle passed to -[NSWindow cacheImageInRect:] is now made integral before caching the image, to avoid antialiasing artifacts.

The following new APIs expose CGS capabilities at the NSWindow level:
// allow for transparent parts in the window - default is opaque = YES
- (void)setOpaque:(BOOL)isOpaque
- (BOOL)isOpaque;
// this call applies an alpha value to the entire window
- (void)setAlphaValue:(float)windowAlpha;
- (float)alphaValue;
NSWindow's setHasShadow: now invalidates the window shadow if the shadow setting changes. This causes the window shadow to be recomputed. Applications which draw custom window shapes may wish to use this method to recompute the window shadow whenever the window shape changes. The recommended way to do this for now is to pair calls to this method:
-(void)customDrawingRoutine {
<draw window shape>
[window setHasShadow:NO];
[window setHasShadow:YES];
}
The following allow additional control over window properties:
// resize window to saved frame.  If flag is YES, resize even if window is non-resizable
- (BOOL)setFrameUsingName:(NSString *)name force:(BOOL)flag;
// indicate whether a window can be hidden during -[NSApplication hide:].  Default is YES
- (void)setCanHide:(BOOL)flag;
- (BOOL)canHide;
// show/hide resize corner (does not effect resizable property)
- (void)setShowsResizeIndicator:(BOOL)show;
- (BOOL)showsResizeIndicator;
The following new API supports animation of window resize:
- (void)setFrame:(NSRect)frameRect display:(BOOL)displayFlag animate:(BOOL)animateFlag;
If animateFlag is YES, a timer is created to animate the transition from the current frame to the new frame. If animateFlag is NO, this call is the same as -setFrame:display:. The view hierarchy is recursively displayed on each resize increment if displayFlag is YES.

The time for the resize animation may be specified by a subclass by overriding:
- (NSTimeInterval)animationResizeTime
The default implementation uses the value for the NSWindowResizeTime user default as the time in seconds to resize by 150 pixels. If unspecified, NSWindowResizeTime is .33 seconds.

Window levels in NSWindow.h are now defined in terms of a function in <CoreGraphics/CGWindowLevel.h>. This means that window levels are no longer constants, so they cannot be used in static initializers. In addition, values of some window levels have changed; for example, NSModalPanelWindowLevel is now less than NSMainMenuWindowLevel, so that modal panels will not appear above menus. Applications which use explicit window levels should rebuild.

Implementation of oneShot windows has changed. The CGSWindowID for a oneShot window is now preserved when the window is closed, but the backing store is freed. Delayed oneShot windows are no longer supported, and hide-on-deactivate windows are explicitly prevented from being oneShot windows, because of a limitation where we cannot guarantee timely redraw for a hide-on-deactivate window.

The following new API allows you to create an NSWindow given a Carbon WindowRef:
@interface NSWindow(NSCarbonExtensions)
// create an NSWindow for a Carbon window - windowRef must be a Carbon WindowRef
- (NSWindow *)initWithWindowRef:(void *)windowRef;
// return the Carbon WindowRef passed into initWithWindowRef:
- (void *)windowRef;
@end
See <HIToolbox/MacWindows.h> for the WindowRef API.


HFS File Type Strings

To support an environment in which the type of a file may be indicated by either a file name extension or an HFS file type, a new form of file type string has been introduced. The file type strings (traditionally file extensions) that are accepted or returned by many Cocoa methods may now contain an encoded HFS file type.

File type strings that contain a file name extension are still acceptable in every situation in which they were acceptable before.

Several new functions, declared in <Foundation/NSHFSFileTypes.h>, have been added to help manage these new file type strings:
NSString *NSFileTypeForHFSTypeCode(OSType hfsFileTypeCode);
Given an HFS file type code, this function returns an autoreleased string that encodes the file type as described above.
OSType NSHFSTypeCodeFromFileType(NSString *fileTypeString);
Given a string of the sort encoded by NSFileTypeForHFSTypeCode(), this function returns the corresponding HFS file type code. It returns zero otherwise.
NSString *NSHFSTypeOfFile(NSString *fullFilePath);
Given the name of a file, this function returns an autoreleased string that encodes the file's HFS file type as described above, or nil if the operation was not successful.

Please use the above functions to convert between type codes and the special encoded strings; do not depend on the exact format of the encoding type string.

The following changes have been made in various classes to take advantage of HFS type strings:

NSDocumentController's -fileExtensionsFromType: now returns an array of file type strings that may contain encoded HFS file types as well as file name extensions. -runModalOpenPanel:forTypes: and -typeFromFileExtension: behave as they always have, but will now accept file type strings that contain encoded HFS file types as well as file name extensions. -openDocumentWithContentsOfFile:display: and -openDocumentWithContentsOfURL:display: now take the HFS file type of files into consideration when deciding what subclass of NSDocument should be instantiated.

NSImage's +imageFileTypes and +imageUnfilteredFileTypes now return arrays of file type strings that may contain encoded HFS file types as well as file name extensions. -initByReferencingFile:, -initWithContentsOfFile:, and -initWithContentsOfURL: now take the HFS file type of files into consideration when deciding what subclass of NSImageRep should be instantiated to represent images in the file.

NSImageRep's +imageFileTypes and +imageUnfilteredFileTypes now return arrays of file type strings that may contain encoded HFS file types as well as file name extensions. +imageRepClassForFileType: behaves as it always has, but will now accept file type strings that contain encoded HFS file types as well as file name extensions. +imageRepWithContentsOfFile:, +imageRepWithContentsOfURL:, +imageRepsWithContentsOfFile:, and +imageRepsWithContentsOfURL: now take the HFS file type of files into consideration when deciding what subclass of NSImageRep should be instantiated.

NSMovie's +movieUnfilteredFileTypes now returns an array of file type strings that may contain encoded HFS file types as well as file name extensions.

NSOpenPanel's -beginSheetForDirectory:file:types:modalForWindow:modalDelegate:didEndSelector:contextInfo:, -runModalForDirectory:file:types:, -runModalForTypes:, and -runModalForDirectory:file:types:relativeToWindow: behave as they always have, but will now accept file type strings that contain encoded HFS file types as well as file name extensions.

In NSSavePanel, file type strings that contain encoded HFS file types are not valid values for the attribute that is accessed by -setRequiredFileType: and -requiredFileType.

NSSound's +soundUnfilteredFileTypes now returns an array of file type strings that may contain encoded HFS file types as well as file name extensions.

NSWorkspace's +iconForFileType: now accepts file type strings that contain encoded HFS file types as well as file name extensions.


Scripting

Since Mac OS X Public Beta, the Scripting and AppKitScripting frameworks have been merged into the Foundation and AppKit frameworks, respectively.

As a result of this, 4 new header files have been added to AppKit.framework/Headers:

- NSApplicationScripting.h
- NSDocumentScripting.h
- NSTextStorageScripting.h
- NSWindowScripting.h

There are still Scripting and AppKitScripting frameworks in Mac OS X, but these are mere stubs whose libraries import Foundation and AppKit libraries and whose header files import Foundation and AppKit header files. They should not be used for new development.

More info about the scripting changes can be found in the Foundation release notes.


NSPageLayout

NSPageLayouts are now displayable as document-modal sheets. A new method has been added:
- (void)beginSheetWithPrintInfo:(NSPrintInfo *)printInfo modalForWindow:(NSWindow *)docWindow delegate:(id)delegate didEndSelector:(SEL)didEndSelector contextInfo:(void *)contextInfo;
This method presents a page layout sheet for printInfo, document-modal relative to docWindow. When the modal session has ended, if neither delegate nor didEndSelector were nil, the method specified by didEndSelector will be invoked on delegate, passing contextInfo as an argument, among others. The method specified by didEndSelector must have the same signature as:
- (void)pageLayoutDidEnd:(NSPageLayout *)pageLayout returnCode:(int)returnCode contextInfo:(void *)contextInfo;
The value of returnCode will be NSCancelButton or NSOKButton.

NSPageLayout is no longer a subclass of NSPanel. It is a direct subclass of NSObject. It is no longer valid to send -[NSView viewWithTag:] to an NSPageLayout.

The action that a method takes has changed: +[NSPageLayout pageLayout] will now return a new instance of NSPageLayout each time it is invoked. There is no shared NSPageLayout.

Some methods have been deprecated:

-[NSPageLayout convertOldFactor:newFactor:] will always set both of its arguments to the same value.
-pickedButton: will never be sent to an NSPageLayout from within AppKit.
-pickedOrientation: will never be sent to an NSPageLayout from within AppKit.
-pickedPaperSize: will never be sent to an NSPageLayout from within AppKit.
-pickedUnits: will never be sent to an NSPageLayout from within AppKit.


NSPrintOperation

The panels that a print operation displays are now displayable as document-modal sheets. A new method has been added:
- (void)runOperationModalForWindow:(NSWindow *)docWindow delegate:(id)delegate didRunSelector:(SEL)didRunSelector contextInfo:(void *)contextInfo;
Assuming that the operation is for printing (and not EPS or PDF copying), this method causes the following actions to be performed by the print operation object, though not necessarily before or after it has returned:
- Unless the value of the attribute that is set by -setShowPanels is NO, an NSPrintPanel is presented as a sheet that is document-modal to docWindow.
- Unless the user has cancelled the operation using the NSPrintPanel, a progress panel that is either document-modal to docWindow, or application-modal, depending on the attribute that is set by -setCanSpawnSeparateThread (see below), is opened. This panel includes, among other things, a Cancel button.
- The operation's view is printed, until cancellation or completion. Whether or not printing is carried out in its own dedicated printing thread depends on the attribute that is set by -setCanSpawnSeparateThread.
- The progress panel is closed.
Upon cancellation or completion, if neither delegate nor didRunSelector were nil, the method specified by didRunSelector will be invoked on delegate, passing contextInfo as an argument, among others. The method specified by didRunSelector must have the same signature as:
- (void)printOperationDidRun:(NSPrintOperation *)printOperation success:(BOOL)success contextInfo:(void *)contextInfo;
The value of success will be YES if the print operation ran to completion without cancellation or error, NO otherwise.

The actual view printing that a print operation does can be made to take place in a dedicated printing thread. A pair of new methods has been added:
- (void)setCanSpawnSeparateThread:(BOOL)canSpawnSeparateThread;
- (BOOL)canSpawnSeparateThread;
The attribute that is accessed using these two methods affects the behavior of -runOperationModalForWindow:delegate:didRunSelector:contextInfo:, unless the operation is for EPS or PDF copying. If it is YES, the progress panel that is shown during printing is shown as a document-modal sheet, and printing is carried out in its own dedicated printing thread, which is automatically created and destroyed by the NSPrintOperation. If It is NO, the progress panel that is shown during printing is shown as an application-modal window, and printing is carried out in the main application thread.

The meanings of some methods deserve clarification:
The attribute that is accessed using -setShowPanels: and -showPanels does not affect whether or not a progress panel is presented by -runOperation or -runOperationModalForWindow:delegate:didRunSelector:contextInfo:, only whether or not an NSPrintPanel is presented.

None of the NSPrintOperation-creating class methods make the created object the current operation for the thread anymore. Instead, a print operation becomes current only when necessary:
- In the -runOperation case, the print operation is made current before any NSPrintPanel might be presented, and is kept current until the print operation has completed or been cancelled.
- In the -runOperationModalForWindow:delegate:didRunSelector:contextInfo: case, the print operation is made current in the thread in which actual view printing is to occur, immediately before view printing begins, and is kept current until view printing has completed or been cancelled.

NSPrintPanel

NSPrintPanels are now displayable as document-modal sheets. A new method has been added:
- (void)beginSheetWithPrintInfo:(NSPrintInfo *)printInfo modalForWindow:(NSWindow *)docWindow delegate:(id)delegate didEndSelector:(SEL)didEndSelector contextInfo:(void *)contextInfo;
This method presents a print panel sheet for printInfo, document-modal relative to docWindow. When the modal session has ended, if neither delegate nor didEndSelector were nil, the method specified by didEndSelector will be invoked on delegate, passing contextInfo as an argument, among others. The method specified by didEndSelector must have the same signature as:
- (void)printPanelDidEnd:(NSPrintPanel *)printPanel returnCode:(int)returnCode contextInfo:(void *)contextInfo;
The value of returnCode will be NSCancelButton or NSOKButton. NSOKButton will be returned even if the user has pressed the Preview button.

NSPrintPanel is no longer a subclass of NSPanel. It is a direct subclass of NSObject. It is no longer valid to send -[NSView viewWithTag:] to an NSPrintPanel.

The action that a method takes has changed: +[NSPrintPanel printPanel] will now return a new instance of NSPrintPanel each time it is sent. There is no shared NSPrintPanel.

Some methods have been deprecated:
-pickedAllPages: will never be sent to an NSPrintPanel from within AppKit.
-pickedButton: will never be sent to an NSPrintPanel from within AppKit.
-pickedLayoutList: will never be sent to an NSPrintPanel from within AppKit.

NSDocument

NSPageLayouts are now displayable by NSDocuments as document-modal sheets. A new method has been added:
- (void)runModalPageLayoutWithPrintInfo:(NSPrintInfo *)printInfo delegate:(id)delegate didRunSelector:(SEL)didRunSelector contextInfo:(void *)contextInfo;
This method presents a page layout sheet for printInfo, document-modally relative to the document's principle window. When the modal session has ended, if neither delegate nor didRunSelector were nil, the method specified by didRunSelector will be invoked on delegate, passing contextInfo as an argument, among others. The method specified by didRunSelector must have the same signature as:
- (void)documentDidRunModalPageLayout:(NSDocument *)document accepted:(BOOL)accepted contextInfo:(void *)contextInfo;
accepted will be YES if the user used the OK button or Return key to dismiss the page layout panel, NO otherwise.

Subclassers of NSDocument are now given an opportunity to prepare any NSPageLayout panel before it is presented to the user. A new method has been added:
- (BOOL)preparePageLayout:(NSPageLayout *)pageLayout;
This method is invoked by -runModalPageLayoutWithPrintInfo: and -runModalPageLayoutWithPrintInfo:delegate:didRunSelector:contextInfo: to do any customization of the pageLayout panel. It returns YES if the panel was successfully prepared, and NO otherwise. The default implementation is empty and returns YES.

The panels that a print operation displays are now displayable by NSDocuments as document-modal sheets. A new method has been added:
- (void)runModalPrintOperation:(NSPrintOperation *)printOperation delegate:(id)delegate didRunSelector:(SEL)didRunSelector contextInfo:(void *)contextInfo;
This method runs printOperation, document-modally relative to the document's principle window. When the operation has finished running, if neither delegate nor didRunSelector were nil, the method specified by didRunSelector will be invoked on delegate, passing contextInfo as an argument, among others. The method specified by didRunSelector must have the same signature as:
- (void)documentDidRunModalPrintOperation:(NSDocument *)document success:(BOOL)success contextInfo:(void *)contextInfo;
The value of success will be YES if the print operation ran to completion without cancellation or error, NO otherwise.

-[NSDocument runPageLayout:] now, instead of invoking -runModalPageLayoutWithPrintInfo:, invokes -runModalPageLayoutWithPrintInfo:delegate:didRunSelector:contextInfo:, with private values for the delegate, didRunSelector, and contextInfo arguments.


NSView

-drawSheetBorderWithSize: will never be sent to an NSView from within AppKit.

There are two new methods added to NSView: -viewDidMoveToWindow and -viewDidMoveToSuperview. The default implementation does nothing. Subclasses of NSView can override these methods to do additional initializations in a new window/superview.


NSFont

NSFont now can now return the number of glyphs in the font:
- (unsigned)numberOfGlyphs;
Two methods have changed their behavior:
+ (void)setUserFixedPitchFont:(NSFont *)aFont;
+ (void)setUserFont:(NSFont *)aFont;
These methods operate on the current application domain, for the keys "NSFixedPitchFont" and "NSFont" respectively. Formerly, there was no programmatic means of removing the defaults for the app domain. These methods have been changed to allow "nil" to be specified as the font argument. In this case, the defaults are removed from the app domain.

The following new method returns the "label" font that is defined in Aqua Human Interface Guidelines:
+ (NSFont *)labelFontOfSize:(float)fontSize;
These methods return the respective font sizes defined in Aqua Human Interface Guidelines:
+ (float)systemFontSize;
+ (float)smallSystemFontSize;
+ (float)labelFontSize;
With combination of these methods, you can query all of Aqua font variations:
System Font [NSFont systemFontOfSize:[NSFont systemFontSize]]
System Font (emphasized) [NSFont boldSystemFontOfSize:[NSFont systemFontSize]]
Small System Font [NSFont systemFontOfSize:[NSFont smallSystemFontSize]]
Small System Font (emphasized) [NSFont boldSystemFontOfSize:[NSFont smallSystemFontSize]]
Application Font [NSFont userFontOfSize:-1.0]
Application Fixed-Pitch Font [NSFont userFixedPitchFontOfSize:-1.0]
Label Font [NSFont labelFontOfSize:[NSFont labelFontSize]]


NSFontPanel

The instance size of NSFontPanel changed since Public Beta. This means any applications subclassing NSFontPanel and adding new instance variables need to be recompiled.


NSSplitView

There are situations in which it is necessary to know whether or not the subview of an NSSplitView is collapsed. A new method has been added:
- (BOOL)isSubviewCollapsed:(NSView *)subview;
This method returns YES if a subview of the NSSplitView is in the collapsed state, NO otherwise.


Pasteboard Type Conversion

There are several pasteboard item types that are mapped directly to their Carbon equivalents, and vice versa, during pasteboard operations that involve both Carbon and Cocoa programs. The list of mapped types includes:

- PDF: Cocoa NSPDFPasteboardType <-> Carbon 'PDF '
- RTF: Cocoa NSRTFPboardType <-> Carbon 'RTF '
- Assorted file, URL, and text types


Help

Applications can provide their own help books by adding plist entries for CFBundleHelpBookFolder and CFBundleHelpBookName. The folder specified by CFBundleHelpBookFolder should contain a localized version of the application's help book. If this help book is specified, it will be opened in HelpViewer when the help menu item is selected.

For more information, please see the "Registering a Help Book" section at http://developer.apple.com/techpubs/macosx/Carbon/HumanInterfaceToolbox/AppleHelp/Apple_Help/index.html

Key binding

In Public Beta, the function keys F1-F4 were mapped to undo:, cut:, copy:, and paste:. We have disabled this mapping, and plan to allow user customization in a future release. However, these bindings can be restored via the Cocoa keybinding mechanism. F5 is still the default keybinding for "complete."


Events

A RightMouseDown in a window of an inactive application will not be delivered to -[NSWindow sendEvent:]. The event will be delivered to -[NSApplication sendEvent:], but the windowNumber will be 0.


Dragging

-draggingSequenceNumber and -draggedImageLocation now work. -draggedImage is valid for local drags.

You can now open documents by dragging them to an application in the dock, and dragging from the titlebar proxy to the desktop will create a link rather than moving the file.

We have added the following new API:
typedef unsigned int NSDragOperation
NSDragOperationMove, NSDragOperationDelete, and NSDragOperationEvery have been added to the list of enumerated values for NSDragOperation. NSDragOperationAll is deprecated.

The dragging source is now told about draggedImage moving, much as the dragging destination is sent draggingUpdated: messages:
- (void)draggedImage:(NSImage *)image movedTo:(NSPoint)screenPoint;
This following method deprecates draggedImage:endedAt:deposited:, and includes an indication of the operation performed by the destination rather than a boolean indicating acceptance.
- (void)draggedImage:(NSImage *)image endedAt:(NSPoint)screenPoint operation:(NSDragOperation)operation;
The dragging destination protocol has one new method, which a destination can implement to be notified when a drag operation ends in some other destination. This might be used by a destination that does auto-expansion in order to collapse any auto-expands. This method is not yet implemented:
- (void)draggingEnded:(id <NSDraggingInfo>)sender

Sheets

The document-modality of sheets is now better enforced. Menu items pertaining to a document and the document's close button are disabled while the document is in a modal state (ie. presenting a sheet).

The modalDelegate is no longer retained by any of the document-modal API. Make sure you do not count on the retaining behavior of the existing doc modal APIs.


NSApplication

With the addition of the document-modal state implied by sheets, it has become difficult for application delegates to respond with YES or NO to -applicationShouldTerminate:. Frequently when asked to terminate, an application wants to present document-modal alerts (sheets) for dirty documents, giving the user the opportunity to save the documents, quit without saving, or cancel the termination.

In order to allow applications to do this without needing to enter some outer modal loop, applicationShouldTerminate:, has been redefined. This method now returns an emumerated type rather than a BOOL. Possible values are: NSTerminateNow to allow the termination to proceed, NSTerminateCancel to cancel the termination, or NSTerminateLater to postpone the decision. If a delegate returns NSTerminateLater, NSApplication will enter a modal loop waiting for a call to -replyToApplicationShouldTerminate. The delegate must call -replyToApplicationShouldTerminate with YES or NO once it is decided whether the application can terminate. NSApplication will run the runloop in NSModalPanelRunLoopMode while waiting for the delegate to make this call.

Unfortunately, this implementation does not allow -[NSApplication terminate:] to be called from a secondary thread. If your application does this, you will get a console error message, and the call to terminate: will have no effect. You can workaround this limitation by messaging the main thread of your application to perform the call to terminate:.

For binary compatibility, a return value of NO is recognized as NSTerminateCancel, and a return value of YES as NSTerminateNow.
// return values for -applicationShouldTerminate:
enum {
NSTerminateNow,
NSTerminateCancel,
NSTerminateLater
} NSApplicationTerminateReply;
@interface NSObject(NSApplicationDelegate)
(NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
...
@end
- (void)replyToApplicationShouldTerminate:(BOOL)shouldTerminate;
hide: and unhide: are now implemented for UIElement apps. If a UIElement application calls -[NSApp hide:], its windows will be hidden and the next app in line will be activated. Because of the menubar feature where it does not show a UIElement app as the active app, this allows the desired behavior where the app that looks active in the menubar actually becomes the active app after the UIElement app hides. -[NSApp unhide:] will activate and show the windows of a UIElement app.


Text drag and drop

NSTextView now supports drag and drop of text. A text selection will be dragged only if the user clicks and holds on it for a certain period of time.

There are two new NSTextView methods to support drag and drop of text. These are primarily for subclassers.

The following method causes textview to begin dragging current selected range, returning YES if it succeeds in initiating the drag:
- (BOOL)dragSelectionWithEvent:(NSEvent *)event offset:(NSSize)mouseOffset slideBack:(BOOL)slideBack;
The following is used by dragSelectionWithEvent:offset:slideBack: to get an appropriate image. Returns the lower-left point of the image in view coordinates as origin. Can be called by others who need such an image, or can be overridden by subclassers to return a different image (if it returns nil, a default icon will be used):
- (NSImage *)dragImageForSelectionWithEvent:(NSEvent *)event origin:(NSPointPointer)origin;
To allow delegates better control over the drag and drop or cut and paste of attachments, two new delegate methods have been added. As an alternative to the existing:
- (void)textView:(NSTextView *)view draggedCell:(id <NSTextAttachmentCell>)cell inRect:(NSRect)rect event:(NSEvent *)event atIndex:(unsigned)charIndex;
we now have:
- (NSArray *)textView:(NSTextView *)view writablePasteboardTypesForCell:(id <NSTextAttachmentCell>)cell atIndex:(unsigned)charIndex;
If the existing method is not used, this method and the next allow the textview to take care of attachment dragging and pasting, with the delegate responsible only for writing the attachment to the pasteboard. In this method, the delegate should return an array of types that it can write to the pasteboard for the given attachment. The following method allows the delegate to write the given attachment to the pasteboard with the given type, and return success or failure:
- (BOOL)textView:(NSTextView *)view writeCell:(id <NSTextAttachmentCell>)cell atIndex:(unsigned)charIndex toPasteboard:(NSPasteboard *)pboard type:(NSString *)type ;

NSLayoutManager

The following two methods have been added to NSLayoutManager:
- (void)setDefaultAttachmentScaling:(NSImageScaling)scaling;
- (NSImageScaling)defaultAttachmentScaling;
They are used to specify the default behavior desired if an attachment image is too large to fit in a text container. Note that attachment cells control their own size and drawing, so this setting can only be advisory for them, but kit-supplied attachment cells will respect it. If the value is not set, NSScaleNone will be used.


NSWorkspace

Most NSWorkspace functionality has now been reenabled. However, certain operating-system-dependent portions of the NSWorkspace functionality are not relevant or not currently implemented on Mac OS X. For example, checkForRemovableMedia and noteUserDefaultsChanged have no effect, and fileSystemChanged and userDefaultsChanged are uninformative; mountNewRemovableMedia is equivalent to mountedRemovableMedia. Also, extendPowerOffBy: is currently unimplemented, and NSWorkspaceWillPowerOffNotification is currently unavailable. The file operations NSWorkspaceCompressOperation, NSWorkspaceDecompressOperation, NSWorkspaceEncryptOperation, and NSWorkspaceDecryptOperation are also currently unavailable.

Three new methods have been added:
- (BOOL)openURL:(NSURL *)url;
This will use a system-dependent means of displaying the given URL to the user, or return NO if NSWorkspace cannot find such a means.
- (BOOL)isFilePackageAtPath:(NSString *)fullPath;
This will determine whether a given directory is in fact a file package. This will also return NO if the given path does not exist, or points to something that is not a directory.
- (NSArray *)mountedLocalVolumePaths
This returns an array containing the mount points of all local volumes, not just the removable ones returned by mountedRemovableMedia.


NSDrawer

A closed drawer, if told to open without a particular edge being specified, will now attempt to choose an edge on which to open based on the space available to display the drawer on-screen. If you need to ensure that a drawer opens on a specific edge, use openOnEdge:.


AppleLanguages

The user's preference order for localizations is stored in the AppleLanguages user default. The value for this should be an array of strings. In the past, the strings in this array have typically been language names ("English", "French", etc.). However, the preferred forms for the strings in this array, and the forms in which they are likely to appear in future, are either as language abbreviations ("en", "fr", etc.) or as locale abbreviations ("en_US", "fr_CA", etc.). Anyone using the value of this default directly must be prepared to accept any of these forms. Direct use of the default is discouraged; in most cases, NSBundle or CFBundle APIs should suffice. See the CFBundle documentation for more details on languages, locales, and localizations.


Services

Services will now be recognized for applications in subdirectories of the usual applications directories, up to 5 levels deep. There is now a default, NSServicesFromNetworkApplications, that controls whether services will be recognized for applications in the network applications directory and its subdirectories; the default value is NO. You should set this default in NSGlobalDomain and log out and log back in for it to take effect.

Service menu entries and command-key equivalents can be localized in two additional ways. The way described in the Services documentation is to make the language names keys in the NSMenuItem and NSKeyEquivalent entries in the NSServices portion of the Info.plist. This has the drawback of placing localized information outside of the .lproj directories. To avoid this drawback, the first alternative is to place the localized values instead in a ServicesMenu.strings file in the appropriate .lproj directories. The keys should be exactly the value of the "default" entries for NSMenuItem and NSKeyEquivalent, and the values should be the localized equivalents. This is the mechanism employed by Apple-supplied applications such as TextEdit, which can be taken as an example of this technique. The second alternative is to copy the NSServices portion of the Info.plist into the InfoPlist.strings. This is less convenient for localization, but more flexible because it allows any portion of NSServices to be altered for localization.


NSColor, NSColorList

The color panel will now display the localized name of a color and color list if one is available. In particular, catalog colors return their localized names through the two methods:
- (NSString *)localizedCatalogNameComponent;
- (NSString *)localizedColorNameComponent;
The localized names for colors and the list are stored in a locaized strings file resource. For example, imagine one wanted to localize /System/Library/Colors/System.clr/ to French. To do so, the strings file: French.lproj/System.strings would have to be added to the System.clr/ directory. The strings file would contain an entry for each color name and for the color list name itself.

Due to a bug, lists with pattern colors could not be written out. Fixing this has required changing the format of the file, which means files with pattern colors cannot be read on older systems. Lists without pattern colors still use the old format for now.


NSTableView

The motion used to start a drag from a table view can now be configured. By default, a new table view will begin drags when either horizontal or vertical mouse motion is encountered. One can control whether vertical motion is treated as a drag or selection change by calling setVerticalMotionCanBeginDrag. A value of NO means that vertical motion will not start a drag.

Note that horizontal motion will always be a valid motion to start a drag. Most often one would disable vertical dragging when it's expected that horizontal dragging is the natural motion.

Finally, the default of treating vertical motion as a drag is a change in behaviour that will be applied to new table views only. So the default for verticalMotionCanBeginDrag is YES for new table views, and NO for existing ones.
- (void)setVerticalMotionCanBeginDrag:(BOOL)flag;
- (BOOL)verticalMotionCanBeginDrag;
The validateDrop methods in NSTableView and NSOutlineView have been updated to use the new NSDragOperation type for dragging, and now appear as:
- (NSDragOperation)tableView:(NSTableView *)tv validateDrop:(id <NSDraggingInfo>)info proposedRow:(int)row proposedDropOperation:(NSTableViewDropOperation)op;
- (NSDragOperation)outlineView:(NSOutlineView *)olv validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)index;

NSOutlineView

NSOutlineViewItemDidCollapseNotification is now posted during item collapse, if appropriate. In particular, the children of a collapsed item will lose their selected status. This has always been the case, but until now NSOutlineView had not posted a selection change notification in this situation.


NSBrowserCell

Selected cells in a browser's last column draw with a slightly darker color than the rest of the browsers columns. Since it can be problematic for cells to know what color their highlight should be, a new method has been introduce in NSBrowserCell to help determine the highlight color that should be used. The method's controlView parameter will generally be the forwarded parameter of the same name from methods like drawInteriorWithFrame:inView:
- (NSColor *)highlightColorInView:(NSView *)controlView;

NSOpenGLView

You can now set the NSOpenGLContext used by the view to allow sharing the same context on a per view basis. This will replace the existing context if one is already been created by the view. Note that this method does not call -[NSOpenGLContext setView:]. You will need to call that method explicitly to synch the context and view.
- (void)setOpenGLContext:(NSOpenGLContext*)context;
There are two new methods that you can override:
- (void)reshape;
- (void)update;
When the visible rectangle or bounds of the view change (for scrolling or resize), you will be notified via the reshape method. The default implementation does nothing. You can use to this adjust the viewport and display frustrum.

If the context needs to be updated because the window moves, the view moves or is resized, the update method is called. This just calls the -[NSOpenGLContext update] method (see below), You should not need to override it unless you need to add locks for multithreaded access to the context. If you do override it, call the super method.


NSOpenGLContext

When an NSOpenGLView changes its location or size, before the call to -[NSOpenGLView reshape] there is a call to a new method in NSOpenGLContext:

- (void)update;

You can override this method if you need to synchronize multiple threads so they block while the context's drawing area is updated.


NSOpenGL Linking

The AppKit now dynamically links in OpenGL the first time it is needed. If your project assumed it was available implicitly, you will now have to import OpenGL.framework explicitly.


Small Controls

For controls that cannot be resized in one direction, we now provide a small control variant that you can use for inspectors and palettes. This variant applies to push buttons, radio buttons, check boxes, sliders, scrollbars, popup buttons, tabs, and progress indicators. You should use the small system font when you set it to use the small control. The valid NSControlSize values are defined in NSCell.h:
typedef enum _NSControlSize {
NSRegularControlSize,
NSSmallControlSize
} NSControlSize;
The classes NSCell, NSTabView, NSScroller, and NSProgressIndicator define a common method that you can use to set and get the control size. This setting is archived.
- (void)setControlSize:(NSControlSize)size;
- (NSControlSize)controlSize;

NSScroller

NSScroller now contains a class method that returns the scroller width for a control size. -[NSScroller scrollerWidth] continues to return the width for a normal sized scrollbar.
+ (float)scrollerWidthForControlSize:(NSControlSize)controlSize;

NSProgressIndicator

NSProgressIndicator now contains methods to set and get the control tint. This behaves the same as in NSCell, etc.
- (NSControlTint)controlTint;
- (void)setControlTint:(NSControlTint)tint;

NSScrollView

-[NSScrollView setDrawsBackground:] now automatically disables copy-on-scroll (setCopiesOnScroll:NO) with NO argument.


NSImage

For compatibility with older applications, the existing NSImage drawing methods such as compositeToPoint: alway draw with only the origin of the image transformed. The image itself is drawn ignoring scale and rotation transforms with the origin at the lower left. While it has been possible to draw with the current transform by getting one of the image's representation and calling its draw method, two new methods have been added to NSImage that do this for you.
- (void)drawAtPoint:(NSPoint)point fromRect:(NSRect)fromRect operation:(NSCompositingOperation)op fraction:(float)delta;
- (void)drawInRect:(NSRect)rect fromRect:(NSRect)fromRect operation:(NSCompositingOperation)op fraction:(float)delta;
If you pass in NSZeroRect for the fromRect: parameter, then the whole image is used. For drawInRect:, the image will be scaled to fit in the destination rectangle as well as transformed with the context's current transform. Please note that if you use these routines in a flipped view, you will need to 'undo' the negative y scale factor and adjust the origin.

One change in NSImage since Mac OS X Server is that NSImage now avoids caching bitmaps in windows whenever it can. From an API point of view, this is mostly transparent to developers; NSImage simply draws the original bitmap instead of the cached version, and avoids creating relatively expensive window server caches. However, this could change the amount of memory your application uses. For instance, a 300 dpi image will end up taking a lot more memory than a 72 dpi cached version. This is especially true if you size the image to be smaller; if the original bitmap is still around, it will represent a lot more memory. Or, an image that is complex to render (say one with an ICC profile) could end up being slower to redraw if beng live-resized or scrolled.

To cause NSImage to cache the bitmap in a window, simply send lockFocus/unlockFocus to it. If the original data is coming from a file, in most circumstances the higher resolution version will automatically be used when resizing or printing the image.


NSMovieView

NSMovieView now works again. The API is almost completely unchanged except for the following: first, the routines to load images via URLs or file paths has been moved to NSMovie. In its place, you can set and get the NSMovie associated with the view. This NSMovie is archived with the view. Please note that like OpenGL, QuickTime is dynamically loaded the first time the view needs to display a movie. If you rely on QuickTime calls before a movie has been displayed, you will need to explicitly link in QuickTime and call EnterMovies before using any QuickTime function calls.
- (void)setMovie:(NSMovie *)movie;
- (NSMovie *)movie;
You can now get a reference to the actual movie controller. Use this to enable features that aren't part of the basic NSMovieView API.
- (void*)movieController;
This is an override point that by default returns [self bounds]. You can return a smaller rectangle to place the movie and its controller in a portion of the view.
- (NSRect)movieRect;

NSMovie

NSMovie is a simple wrapper around a QuickTime Movie reference. When an NSMovie instance is deallocated, DisposeMovie is called. You can create your own Movie, or load a movie via a URL (currently, only file based movies are supported) or via the pasteboard. If you pass in YES for initWithURL:byReference:, then the URL is archived. Otherwise, a Movie reference is archived (not including the actual media data).
- (id)initWithMovie:(void *)movie;
- (id)initWithURL:(NSURL *)url byReference:(BOOL)byRef;
- (id)initWithPasteboard:(NSPasteboard *)pasteboard;
This will get a reference to the QuickTime movie. Do not dispose of it directly.
- (void *)QTMovie;
If the NSMovie was created with a URL, this will return it.
- (NSURL *)URL;
These return a information about movie file types and pasteboard types and whether the pasteboard contains a movie. The default file type extension is '.mov'
+ (NSArray *)movieUnfilteredFileTypes;
+ (NSArray *)movieUnfilteredPasteboardTypes;
+ (BOOL)canInitWithPasteboard:(NSPasteboard *)pasteboard;

NSBitmapImageRep

NSBitmapImageRep now uses any associated ColorSync data (aka ICC profiles) when rendering. It will also read and write the data for JPEG and PNG as well as TIFF. You can set and get the data via the NSImageColorSyncProfileData property.

Targa and MacPaint importing via NSData is temporarily disabled. Importing via QuickTime Graphics Importers still works for other listed types.


NSButtonCell

There are two new types of button bezel defined in NSButtonCell.h:
NSShadowlessSquareBezelStyle = 6
The 'shadowless square bezel' is s similar to the NSRegularSquareBezelStyle but has no shadow so you can abut the cells without having overlapping shadows. These might be used for a tool palette.
NSCircularBezelStyle = 7
This is a round button with room for small icon or single character. It has regular and small variants. Note that the large variant only comes in gray at this time.


NSGraphicsContext

There are new methods to get and set the antialiasing and interpolation (image smoothing) attributes in a context. Note that these values are not part of a the graphics state and so you cannot use restoreGraphicsState to reset the state after setting. NSImageInterpolationDefault is dependent on the type of context.
typedef enum NSImageInterpolation {
NSImageInterpolationDefault,
NSImageInterpolationNone,
NSImageInterpolationLow,
NSImageInterpolationHigh
} NSImageInterpolation;
- (void)setShouldAntialias:(BOOL)antialias;
- (BOOL)shouldAntialias;
- (void)setImageInterpolation:(NSImageInterpolation)interpolation;
- (NSImageInterpolation)imageInterpolation;

NSGraphics

A new frame rectangle function has been added that lets you specify a compositing operation as well as a width. It behaves just like NSFrameRectWithWidth but isn't constrained to use NSCompositeCopy.
void NSFrameRectWithWidthUsingOperation(NSRect rect, float width, NSCompositingOperation op);

NSSavePanel, NSOpenPanel

In order to free up unused memory after dismissing a save or open panel, we now release the accessory view after the panel is closed. If you relied on the panel to hold on to the accessory view until the next time you set it, the accessory view may be deallocated unexpectedly. If you retain it in your own code, no change is required.

NSSavePanel now provides a delegate method which gives the delegate the opportunity to validate the filename entered by the user:
- (NSString *)panel:(id)sender userEnteredFilename:(NSString *)filename confirmed:(BOOL)okFlag;
When the user confirms their filename choice by hitting OK or <Return>, this method is called with their filename. The delegate can either leave the filename alone, or return a new filename, or return nil to cancel the save (and leave the save panel as is, similar to panel:isValidFilename:).

This method is called before any required extension is appended onto the name, and before the save panel presents the "are you sure you wish to replace existing file?" dialog.

Note that in the future this method may be called multiple times during a session, as the user is typing. In those cases, the okFlag will be NO until the user actually confirms their choice, in which case okFlag will be YES. If the delegate does expensive validation, or puts up alerts, it should do so only in this latter case.


Aliases

Unlike symbolic links, Mac OS aliases are currently not handled automatically by the AppKit or underlying Foundation and POSIX libraries. This can mean that files returned by NSOpenPanel may point to aliases and will need to be resolved in order to find the original item. Here is a function that you can use to make sure the path you have points to a real file and not an alias. The function returns the original string if it didn't point to an alias. This means going from a path to a URL to an FSRef, resolving, and going back again.
#import <Carbon/Aliases.h>
NSString* ResolveAliasPath(NSString* path)
{
CFStringRef resolvedPath = nil;
CFURLRef url = CFURLCreateWithFileSystemPath(NULL /*allocator*/, (CFStringRef)path, kCFURLPOSIXPathStyle, NO /*isDirectory*/);
if (url != NULL) {
FSRef fsRef;
if (CFURLGetFSRef(url, &fsRef)) {
Boolean targetIsFolder, wasAliased;
if (FSResolveAliasFile (&fsRef, true /*resolveAliasChains*/, &targetIsFolder, &wasAliased) == noErr && wasAliased) {
CFURLRef resolvedurl = CFURLCreateFromFSRef(NULL /*allocator*/, &fsRef);
if (resolvedurl != NULL) {
resolvedPath = CFURLCopyFileSystemPath(resolvedurl, kCFURLPOSIXPathStyle);
CFRelease(resolvedurl);
}
}
}
CFRelease(url);
}
return resolvedPath != nil ? [(NSString*)resolvedPath autorelease] : path;
}
Note that one place where aliases are automatically resolved is when documents are double-clicked in the Finder, or dragged to your app icon.


Find submenu

The "Enter Selection" item in the standard "Find" submenu was changed to "Use Selection for Find". The new application template has been updated, but existing apps need to also change this explicitly.


Underline vs Revert to Saved

Aqua Interface Guidelines state that the cmd-u shortcut is to be used for "Underline" rather than "Revert to Saved." We have changed the menu template for new apps; however, existing apps need to do this change by hand. There is no longer a recommended shortcut for "Revert to Saved."


NSMenu

NSMenu now uses Carbon Menu Manager for key equivalent handling to achieve full compatibility in command key behavior with Carbon. Specifically, the class now uses IsMenuKeyEvent() function to determine the NSMenuItem the event is supposed to activate.


NSBezierPath

All operations are protected by gsave/grestore so applications don't have to care about the graphics setting (miter limit, line width, etc).


TIFF files with alpha (transparency)

When loading TIFF files into Cocoa apps, you might sometimes see the following warning in the console: "Warning: TIFF image with unknown extra samples assumed to have unassociated alpha. RGB values have been premultiplied."

Cocoa and Quartz expect bitmaps with alpha to have the color values premultiplied. Whenever a TIFF file without premultiplication is loaded using NSImage or NSBitmapImageRep, Cocoa will premultiply the image for you. There's a slight performance hit to this, so it's best to premultiply the images ahead of time.

Some paint applications do not do premultiplication, and in addition, they are not quite clear in stating what they do with regards to alpha. In those cases you will get the above warning.

You can fix such files by loading and saving them once in a Cocoa app. The "tiffutil" command line utility can be used to do this. In a Terminal window, you can do:
tiffutil -cat orig.tiff -out new.tiff
This will read orig.tiff and write it out as new.tiff. If you run tiffutil without any arguments, it will tell you other arguments it accepts.


RTF files

We now handle the following new keys in the documentAttributes dictionary when reading/writing RTF files:

@"ViewSize": View size for the document, NSValue containing NSSize
@"ViewZoom": Zoom value, NSValue containing float; 100 == 100% zoom
@"ViewMode": View mode of the document, NSValue containing int; 0 = none (usually wrap-to-window or container mode); 1 = page layout (use value of @"PaperSize")

TextEdit used to store the view size in @"PaperSize". It no longer does this, however, it will try to correctly pick up the view size from older documents which did this.

Because RTF support does not properly handle tables, copy/paste of tables from applications such as Excel might fail to display the table properly in a rich text document (including rich compose windows in Mail.) In those cases, one easy workaround is to paste into a plain text document, which causes the plain text alternative of the data to be used. Then the plain text table can be copy/pasted into the rich text document.


NSTextStorage

A new attribute, NSCharacterShapeAttributeName, is now supported by the text system. The attribute controls glyph shape variation supported by Hiragino Japanese fonts. The value is an integer corresponding to Apple Type Services kCharacterShapeType feature selector value. The value 0 is interpreted to disable the feature, and other value is corresponding selector value plus 1. See SFNTLayoutTypes.h in ATS.framework.


NSTextView

A new method, -toggleTraditionalCharacterShape:, is added to NSTextView. This method toggles the NSCharacterShapeAttributeName attribute at the current selection. It adds/removes NSCharacterShapeAttributeName with the integer value 1 (kTraditionalCharactersSelector + 1).


NSSound

There is a new init method for NSSound instances, -initWithData:, which takes an NSData containing the sound data. The magic number(s) in the sound header in the data are used to determine the format of the samples.


Info.plist

Please refer to the Info.plist release note for changes pertaining to the way bundle and document type information is declared in applications.



Notes specific to Mac OS X Public Beta

Graphite

This release introduces the "Graphite" color variant for Aqua. This variant is user-selectable through the Preferences application; however, it is not selectable programmatically on a per-control basis. This means that there is no explicit NSControlTint value for Graphite; instead, the tint corresponding to NSDefaultControlTint changes.

When the user changes this setting, applications are notified immediately; all standard controls react to this by redisplaying themselves. Applications can register for the NSControlTintDidChangeNotification to do further cleanup; this is useful if they have custom controls or have image caches that might need to be recreated, for instance. Applications can find out the color value of the current default tint setting by calling [NSColor colorForControlTint:NSDefaultControlTint].


NSBezierPath

In Beta, NSBezierPath has added the following methods:
- (float)miterLimit;
- (void)setMiterLimit:(float)miterLimit;
- (float)flatness;
- (void)setFlatness:(float)flatness;
- (void)getLineDash:(float *)pattern count:(int *)count phase:(float *)phase;
- (void)setLineDash:(const float *)pattern count:(int)count phase:(float)phase;
These allow you to set and retrieve the miter limit, flatness, or line dash pattern on a particular path.


NSOpenPanel / NSSavePanel

The semantics of setPrompt: method in open and save panels has changed. With the Aqua UI, the "prompt" in front of the text field is always set to "Go to:" and cannot be changed. The method setPrompt: has been disabled in previous Aqua releases. It has now been re-targeted to affect the default button (which could not formerly be set via API). The default text on the default button is now "Open" for the open panel and "Save" for the save panel, but can be modified programmatically. Since this API formerly affected a text field, any colon on the end of the string is removed before being used on the button.

The setTitle: methods in open and save panels have been re-enabled as well, and affect the title text of the panels.

It is intended that programmers will use short words or phrases, such as "Open", "Save", "Set", or "Choose" on the button. At this time, the button is not re-sized to fit the text when set; this is a bug that should be addressed soon.


Font Directories

A new implementation has been added to bring back the concept of different font directories for User, System, and Network. This functionality is usually handled automatically by running "fcache" from the "pbs" process when a user logs in. At system boot time, the "fcache" program is run for the System and Local font directories. When a user logs in, it is run for the user's home directory. The program can also be run by hand in specific domains, and a new set of command-line arguments is provided for ease-of-use: -system, -user, -local, and -network.


Printing

The final release of Mac OS X will include substantial changes to the printing-related classes; some of these changes are outlined below.

NSPageLayout:

NSPageLayouts will be displayable as document-modal sheets. New methods are being added to make this possible.

NSPageLayout will no longer be a subclass of NSPanel. It will be a direct subclass of NSObject. It will not be possible to send -[NSView viewWithTag:] to an NSPageLayout.

Some methods are being deprecated:

-convertOldFactor:newFactor:will always set both of its arguments to the same value.
-pickedButton:will never be sent from within AppKit.
-pickedOrientation:will never be sent from within AppKit.
-pickedPaperSize:will never be sent from within AppKit.
-pickedUnits:will never be sent from within AppKit.

Accessory views will be supported. It is possible that new methods wil be added for use by accessory views.

NSPrintOperation:

The panels that a print operation displays will be displayable as document-modal sheets. New methods are being added to make this possible.

The meanings of some methods are being reevaluated:

+currentOperation and +setCurrentOperation: imply that there is one and only one current NSPrintOperation. There will be more than one current NSPrintOperation in the future.

Accessory views will be supported. It is possible that new methods will be provided for use by accessory views.

NSPrinter:

The purpose of the NSPrinter class and each of its methods is being reevaluated.

NSPrintInfo:

Some attribute settings that were stored as entries in the dictionary assocated with an NSPrintInfo are being deprecated. Such entries will be ignored by -[NSPrintInfo initWithDictionary:], and will not be present in any dictionary returned by -[NSPrintInfo dictionary]. They are:

NSPrintFaxCoverSheetName
NSPrintFaxModem
NSPrintFaxHighResolution
NSPrintFaxReceiverNames
NSPrintFaxReceiverNumbers
NSPrintFaxReturnReceipt
NSPrintFaxSendTime
NSPrintFaxTrimPageEnds
NSPrintFaxUseCoverSheet

A job disposition is being deprecated:

-setJobDisposition:will treatNSPrintFaxJobas if it were synonymous withNSPrintSpoolJob.
-jobDispositionwill never returnNSPrintFaxJob.

A method may be deprecated. If so:

+sizeForPaperName:will always returnNSZeroSize, regardless of the paper name.

The meanings of some attribute settings are being reevaluated. They are:

NSPrintFormName
NSPrintJobFeatures
NSPrintPaperFeed
NSPrintPrinter

NSPrintPanel:

NSPrintPanels will be displayable as document-modal sheets. New methods are being added to make this possible.

NSPrintPanel will no longer be a subclass of NSPanel. It will be a direct subclass of NSObject.

Some methods are being deprecated:

-pickedAllPages:will never be sent from within AppKit.
-pickedButton:will never be sent from within AppKit.
-pickedLayoutList:will never be sent from within AppKit.

Accessory views will be supported. It is possible that new methods will be provided for use by accessory views.

NSDocument:

NSPageLayouts will be displayable by NSDocuments as document-modal sheets. New methods are being added, and the meanings of others modified, to make this easy.

NSWindow:

The behavior of the -print method may change so as to display panels as document-modal sheets.


NSWindow

Hiding an application now releases the backing store for any oneShot windows. Minimizing a oneShot window also releases the backing store. Any views doing custom drawing (outside of the standard display mechanism) which may try to draw while the application is hidden or the window is minimized should use -[NSView lockFocusIfCanDraw] rather than -[NSView lockFocus].

There is a user default, AppleDockIconEnabled, to enable setting the image in a minimized window tile with -[NSWindow setMiniwindowImage:]. The image will be scaled as necessary to fit the tile. This behavior is off by default, so you must set AppleDockIconEnabled to YES if you want to enable this behavior. Our intent is to enable this behavior in the next release; however, in most cases applications might not want to set the miniwindow icon explicitly.

Single window mode has been disabled in Public Beta.


NSApplication

The image in the dock application tile can be set with -[NSApplication setApplicationIconImage:]. The image will be scaled as necessary to fit the tile.

You can call -postEvent:atStart: and -discardEventsMatchingMask:beforeEvent: methods from subthreads. Events posted in subthreads bubble up in the main thread event queue.


NSWorkspace

Icons returned by NSWorkspace methods now include thumbnail representations (128x128) if available. They are also created as images of size 32x32, rather than images of undetermined size. Previously their actual displayed sizes were left to depend on the representations available.


Document modal API

The document modal API introduced in DP4 is now implemented in NSDocument, NSDocumentController, and NSOpenPanel. The DP3 document modal API is deprecated, and calls to these deprecated methods will result in warnings to the console. We have turned off these warnings for applications found under /Applications or /Developer/Applications. We encourage developers to test their applications for these warnings before installing their application in /Applications or /Developer/Applications.

Each method takes a modalDelegate, a callback, and an optional contextInfo argument. When the document-modal session is ended, the modalDelegate is invoked with the callback method, which receives the sheetWindow object, the result of running the sheet - either a boolean or a returnCode, and the contextInfo argument. The contextInfo is a way for you to pass information from the start of the modal session to the end, and can be a simple value, a structure, or an object.

The callback is invoked before dismissing the sheet in order to give you the opportunity to dismiss the sheet and the parent document window at the same time. For example, you might want to do this when dismissing a "do you want to save" alert before closing a window. If the user selects "don't save", you want to close both the document window and the sheet without the sheet effect. This can be accomplished by calling [docWindow close ] from the callback. You can also dismiss just the sheet in this method by calling [sheetWindow orderOut:]. If you do not dismiss the sheet, it will be done for you on return from your callback, but you may be in a situation where you want to immediately present another sheet, and this is probably best done from your callback after dimissing the first one.

The NSRunAlertSheet variants take two callbacks, one which is invoked before dismissing the alert sheet, and the other which is invoked afterwards. You may find it convenient to implement both methods, but it is not required.

NSDocument:
- (IBAction)saveDocument:(id)sender
- (IBAction)saveDocumentAs:(id)sender
- (IBAction)saveDocumentTo:(id)sender
These methods now call the new document modal API below.

saveDocument: calls -saveDocumentWithDelegate:didSaveSelector:contextInfo:.
saveDocumentAs: and saveDocumentTo: call -saveToFile:saveOperation:delegate:didSaveSelector:contextInfo:.

This means that these calls are now asynchronous - they may return before the save operation has completed (and the save sheet may still be present on the document).
- (void)shouldCloseWindowController:(NSWindowController *)windowController delegate:(id)delegate shouldCloseSelector:(SEL)callback contextInfo:(void *)contextInfo
This method replaces shouldCloseWindowController:. This method will invoke the callback with the result of canCloseDocumentWithDelegate:shouldCloseSelector:contextInfo: if the window controller that is closing is the last one or is marked as causing the document to close. Otherwise it invokes the callback with YES. This is called automatically by NSWindow for any window which has a window controller and a document associated with it. NSWindow calls this prior to asking its delegate -windowShouldClose:.

shouldCloseSelector should have the following signature:
- (void)document:(NSDocument *)document shouldClose:(BOOL)shouldClose contextInfo:(void *)contextInfo
- (void)canCloseDocumentWithDelegate:(id)delegate shouldCloseSelector:(SEL)shouldCloseSelector contextInfo:(void *)contextInfo
This method replaces canCloseDocument. If the document is not dirty, this method will immediately call the callback with YES. If the document is dirty, an alert will be presented giving the user a chance to save, not save or cancel. If the user chooses to save, this method will save the document. If the save completes successfully, this method will call the callback with YES. If the save is cancelled or otherwise unsuccessful, this method will call the callback with NO. This method is called by shouldCloseWindowController: sometimes. It is also called by NSDocumentController's -closeAllDocuments. You should call it before you call -close if you are closing the document and want to give the user a chance save any edits.

shouldCloseSelector should have the following signature:
- (void)document:(NSDocument *)doc shouldClose:(BOOL)shouldClose contextInfo:(void *)contextInfo
- (void)saveDocumentWithDelegate:(id)delegate didSaveSelector:(SEL)didSaveSelector contextInfo:(void *)contextInfo
This method partially replaces fileNameFromRunningSavePanelForSaveOperation:. This method runs the save panel and invokes saveToFile:saveOperation:delegate:didSaveSelector:contextInfo: with the result. It is called from the -saveDocument: action method, and from canCloseDocumentWithDelegate:shouldCloseSelector:contextInfo: if the user chooses to save.

didSaveSelector should have the following signature:
- (void)document:(NSDocument *)doc didSave:(BOOL)didSave contextInfo:(void *)contextInfo
- (void)saveToFile:(NSString *)fileName saveOperation:(NSSaveOperationType)saveOperation delegate:(id)delegate didSaveSelector:(SEL)didSaveSelector contextInfo:(void *)contextInfo
This method partially replaces fileNameFromRunningSavePanelForSaveOperation:. This method gets called after the user has been given the opportunity to select a destination through the modal save panel presented by runModalSavePanelForSaveOperation:delegate:didSaveSelector:contextInfo:. If fileName is non-nil, this method writes the document to fileName, sets the document's file location and document type (if a native type), and clears the document's edited status. didSaveSelector gets called with YES if the document is saved successfully and NO otherwise.

didSaveSelector should have the following signature:
- (void)document:(NSDocument *)doc didSave:(BOOL)didSave contextInfo:(void *)contextInfo
- (void)runModalSavePanelForSaveOperation:(NSSaveOperationType)saveOperation delegate:(id)delegate didSaveSelector:(SEL)didSaveSelector contextInfo:(void *)contextInfo
This method replacesrunModalSavePanel:withAccessoryView:. This method prepares and runs the modal save panel. It is invoked fromsaveDocumentWithDelegate:didSaveSelector:contextInfo:, and the action methodssaveDocumentAs:, andsaveDocumentTo:. This method will callprepareSavePanel:to allow further customization of the savePanel.

didSaveSelector should have the following signature:
- (void)document:(NSDocument *)doc didSave:(BOOL)didSave contextInfo:(void *)contextInfo
- (BOOL)prepareSavePanel:(NSSavePanel *)savePanel
This method is invoked byrunModalSavePanelForSaveOperation:delegate:didSaveSelector:contextInfo:to do any customization of the save panel. It returns YES if successfully prepared, and NO otherwise. The default implementation is empty and returns YES.

NSDocumentController:
- (void)closeAllDocumentsWithDelegate:(id)delegate didCloseAllSelector:(SEL)didAllCloseSelector contextInfo:(void *)contextInfo
This method replacescloseAllDocuments. This method goes through all the open documents and tries to close them one by one. Each NSDocument is sent-canCloseDocument:didCloseSelector:contextInfowhich, if it is dirty, gives it a chance to refuse to close or to save itself first and may put up UI to ask whether to save or to perform a save.

didCloseAllSelector is invoked with YES if all documents are closed, and NO otherwise. It should have the following signature:
- (void)documentController:(NSDocumentController *)docController didCloseAll:(BOOL)didCloseAll contextInfo:(void *)contextInfo
- (void)reviewUnsavedDocumentsWithAlertTitle:(NSString *)title cancellable:(BOOL)cancellable delegate:(id)delegate didReviewAllSelector:(SEL)didReviewAllSelector contextInfo:(void *)contextInfo
This method replaces reviewUnsavedDocumentsWithAlertTitle:cancellable:. It displays an alert panel asking users if they want to review unsaved documents, quit regardless of unsaved documents, or (if flag is YES) if they want to cancel the impending save operation. This method invokes didReviewAllSelector with YES if quit without saving is chosen or if there are no dirty documents, and NO otherwise.If the user selects the Review Unsaved option, closeAllDocumentsWithDelegate:didCloseAllSelector:contextInfo: is invoked. This method is invoked when users choose the Quit menu command and when the computer power is being turned off (in which case, flag is NO).

didReviewAllSelector should have the following signature:
- (void)documentController:(NSDocumentController *)docController didReviewAll:(BOOL)didReviewAll contextInfo:(void *)contextInfo
NSOpenPanel:
- (void)beginSheetForDirectory:(NSString *)path file:(NSString *)name types:(NSArray *)fileTypes modalForWindow:(NSWindow *)docWindow modalDelegate:(id)delegate didEndSelector:(SEL)didEndSelector contextInfo:(void *)contextInfo
This method replaces runModalForDirectory:file:types:relativeToWindow:. This method presents an open panel sheet on docWindow. When the modal session is ended, the didEndSelector will be invoked.

The didEndSelector method should have the following signature:
- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo

Dragging

Dragging has some known problems. You cannot drag multiple items between the Desktop and Cocoa applications; you can only drag single items correctly between the applications.

-(NSImage *)draggedImage always returns nil, and -(int)draggingSequenceNumber returns 0.


NSTextAttachmentCell methods

The NSTextAttachmentCell protocol has the following additional methods, which complex conformers may implement for more precise control over drawing and mouse tracking:
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView characterIndex:(unsigned)charIndex layoutManager:(NSLayoutManager *)layoutManager;
- (BOOL)wantsToTrackMouseForEvent:(NSEvent *)theEvent inRect:(NSRect)cellFrame ofView:(NSView *)controlView atCharacterIndex:(unsigned)charIndex;
The wantsToTrackMouse method allows an attachment to specify whether it ever wishes to track the mouse; if it returns YES, then the new wantsToTrackMouseForEvent:inRect:ofView:atCharacterIndex: allows the attachment to decide whether it wishes to do so for particular events.


Drag And Drop Support in NSTableView and NSOutlineView

TableView and OutlineView now support drag & drop. To use this, all that is necessary is to adopt optional API found in NSTableViewDataSource, and NSOutlineViewDataSource. To modify the default drag image, one may override a new method found in NSTableView.

Dragging Related DataSource Protocols:

To be a dragging source, the data source must implement the appropriate writeItems:toPasteboard: method. This method is called when the view determines a mouse event is the beginning of a drag. This is the data source's chance to cancel the drag, or supply the data for the rows, or items that are participating in the drag.

To be a dragging destination, the data source must implement the appropriate validateDrop:, and acceptDrop: methods. As a drag proceeds, the view needs to continually determine where the drop should end up if the mouse were released. Based on the mouse location, the view will negotiate where the potential drop would occur so that it can highlight the drop location for visual feedback.The drop location is negotiated with the validateDrop: method.

Since there is support for both between and on rows drop types, the negotiation for a drop location requires a short explanation. Assume a table view rows numbered from 0 to N-1 starting with the top most row. Now, imagine the mouse is over a row R of a table view. If the mouse is actually closer to row R+1 than the middle of row R the table view will first try to negotiate a drop between row R, and R+1. If the data source rejects that proposal, then the table view will propose dropping on row R itself. Finally, when the mouse is released, the data source will be sent an acceptDrop: so that it can incorporate the dropped data at the previously negotiated location.
typedef enum { NSTableViewDropOn, NSTableViewDropAbove } NSTableViewDropOperation;
In drag and drop, this enum is used to specify a dropOperation. For example, given a table with N rows (numbered with row 0 at the top visually), a row of N-1 and operation of NSTableViewDropOn would specify a drop on the last row. To specify a drop below the last row, one would use a row of N and NSTableViewDropAbove for the operation.
@interface NSObject (NSTableViewDataSource)
- (BOOL)tableView:(NSTableView *)tv writeRows:(NSArray*)rows toPasteboard:(NSPasteboard*)pboard;
This above method is called after it has been determined that a drag should begin, but before the drag has been started. To refuse the drag, return NO. To start a drag, return YES and place the drag data onto the pasteboard (data, owner, etc...). The drag image and other drag related information will be set up and provided by the table view once this call returns with YES. The rows array is the list of row numbers that will be participating in the drag.
- (unsigned int)tableView:(NSTableView*)tv validateDrop:(id <NSDraggingInfo>)info proposedRow:(int)row proposedDropOperation:(NSTableViewDropOperation)op;
This method is used by NSTableView to determine a valid drop target. Based on the mouse position, the table view will suggest a proposed drop location. This method must return a value that indicates which dragging operation the data source will perform. The data source may "re-target" a drop if desired by calling setDropRow:dropOperation: and returning something other than NSDragOperationNone. One may choose to re-target for various reasons (eg. for better visual feedback when inserting into a sorted position).
- (BOOL)tableView:(NSTableView*)tv acceptDrop:(id <NSDraggingInfo>)info row:(int)row dropOperation:(NSTableViewDropOperation)op;
This method is called when the mouse is released over an outline view that previously decided to allow a drop via the validateDrop method. The data source should incorporate the data from the dragging pasteboard at this time.
@end
The following value may be used as a valid childIndex of a drop target item. In this case, the drop will happen directly on the target item.
enum { NSOutlineViewDropOnItemIndex = -1 };
@interface NSObject (NSOutlineViewDataSource)
- (BOOL)outlineView:(NSOutlineView *)olv writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard;
This method is called after it has been determined that a drag should begin, but before the drag has been started. To refuse the drag, return NO. To start a drag, return YES and place the drag data onto the pasteboard (data, owner, etc...). The drag image and other drag related information will be set up and provided by the outline view once this call returns with YES. The items array is the list of items that will be participating in the drag.
- (unsigned int)outlineView:(NSOutlineView*)olv validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)index;
The above method is used by NSOutlineView to determine a valid drop target. Based on the mouse position, the outline view will suggest a proposed drop location. This method must return a value that indicates which dragging operation the data source will perform. The data source may "re-target" a drop if desired by calling setDropItem:dropChildIndex: and returning something other than NSDragOperationNone. One may choose to re-target for various reasons (eg. for better visual feedback when inserting into a sorted position).
- (BOOL)outlineView:(NSOutlineView*)olv acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(int)index;
This method is called when the mouse is released over an outline view that previously decided to allow a drop via the validateDrop method. The data source should incorporate the data from the dragging pasteboard at this time.
@end
Notes:

- NSTableView and NSOutlineView will not register for any drag types, it is up to the client to do this.
- NSTableView and NSOutlineView allow you to drag and drop just about anywhere. However, if the source and destination are the same view, there are certain scenarios to keep in mind.The implementation will not attempt to drop on the same row you dragged from. This is filtered out. However, the implementation does not filter out an attempt to drop an item into one of its descendants. Though generally this action does not make sense, the implementation does not suppress it since some clients may want this behavior.

Retargeting of Drop Target Location:

When the data source receives validateDrop: it must return a value indicating wether or not the proposed drop can be accepted. At this time, the data source may re-target the drop location, for instance, to show that a dragged .h file will end up in the group of h files. To support re-targeting of the suggested location, we have added one new method to NSTableView and NSOutlineView respectively.
@interface NSTableView ...
- (void)setDropRow:(int)row dropOperation:(NSTableViewDropOperation)op;
To be used from validateDrop: if you wish to "re-target" the proposed drop. To specify a drop on the second row, one would specify row=2, and op=NSTableViewDropOn. To specify a drop below the last row, one would specify row=[tv numberOfRows], and op=NSTableViewDropAbove.
@end
@interface NSOutlineView ...
- (void)setDropItem:(id)item dropChildIndex:(int)index;
To be used from validateDrop: in order to "re-target" the proposed drop. To specify a drop on an item I, one would specify item=I, and index=NSOutlineViewDropOnItemIndex. To specify a drop between child 2 and 3 of an item I, on would specify item=I, and index=3 (children are zero-base indexed). To specify a drop on an un-expandable item I, one would specify item=I, and index=NSOutlineViewDropOnItemIndex.
@end
Affecting the Default Dragging Behavior:

By default, when a user drags out of a table or outline view, it will appear as if they are dragging a copy of the cells (usually text cells). Table views will display the entire row, while outline views will only display the outline column of each row. To use a custom drag image instead, override dragImageForRows:event:dragImageOffset:.
@interface NSTableView ...
- (NSImage*)dragImageForRows:(NSArray*)dragRows event:(NSEvent*)dragEvent dragImageOffset:(NSPointPointer)dragImageOffset;
This method computes and returns an image to use for dragging. Override this to return a custom image. 'dragRows' represents the rows participating in the drag. 'dragEvent' is a reference to the mouse down event that began the drag. 'dragImageOffset' is an in/out parameter. This method will be called with dragImageOffset set to NSZeroPoint, but it can be modified to re-position the returned image. A dragImageOffset of NSZeroPoint will cause the image to be centered under the mouse.
@end
Common Pitfalls:

It is important to keep in mind a few things when implementing your data source.First, you will always be sent valid proposals. If you choose to re-target the drop, you must make sure that the drop target is valid. Secondly, NSTableView and NSOutlineView support "on" and "between" kind of drops. This means you will potentially be sent two message when the view is trying to determine where to target a drop. For example, if you are very close to the top of a row, the implementation will first suggest a drop between that row and the one above it. However, if you return NSDragOperationNone (maybe you only want "on" type drops), the implementation will suggest a drop "on" the row itself. And of course, if you are closer to the middle of the row that the edge, an "on" drop will be tried before a "between" kind of drop.

So, imagine you only want to accept "on" type drops. A common mistake can be seen in the following code segment:
- (unsigned int)tableView:(NSTableView*)tv validateDrop:(id <NSDraggingInfo>)info proposedRow:(int)row proposedDropOperation:(NSTableViewDropOperation)op {
...
// Decide if we want to accept the data in info...
...
if (weWantThisData) {
[tv setDropRow: row dropOperation: NSTableViewDropOn];
return NSDragOperationAll;
} else {
return NSDragOperationNone;
}
}
The implementer has forgotten that a row of N (where the table has rows 0 through N-1) and operation of type NSTableViewDropAbove is valid. This means that it is legal for NSTableView to propose N and NSTableViewDropAbove as the drop target (ie. to suggest a drop "below" the last row). Unfortunately, in this situation, the above segment will end up retargeting the drop to be "on" row N, which doesn't make any sense! The above code segment should have been:
- (unsigned int)tableView:(NSTableView*)tv validateDrop:(id <NSDraggingInfo>)info proposedRow:(int)row proposedDropOperation:(NSTableViewDropOperation)op {
if (op==NSTableViewDropOn) {
...
// Decide if we want to accept the data in info...
...
if (weWantThisData) {
return NSDragOperationAll;
} else {
return NSDragOperationNone;
}
} else {
return NSDragOperationNone;
}
}
Auto Expansion Support in NSOutlineView:

The drag and drop support for NSOutlineView comes with a new auto expansion feature. As a drag proceeds over a drop capable outline view, expandable items will automatically expand (after a small delay) as the mouse hovers over them.

When a drag has finished, the outline view may decide to automatically collapse these items (after a small delay) to return the outline view back to its original state. By default, if a drop is successful (as indicated by the return value fromacceptDrop:), the items will remain open. If a drop fails, the items will collapse and return to their original state. To change this behavior, one should override the following method in NSOutlineView:
@interface NSOutlineView ...
- (BOOL)shouldCollapseAutoExpandedItemsForDeposited:(BOOL)deposited;
This method returns YES to indicate that auto expanded items should return to their original collapsed state. Override this method to provide custom behavior. 'deposited' tells whether or not the drop terminated due to a successful drop (as indicated by the return value from acceptDrop:). Note that exiting the view will be treated the same as a failed drop.
@end
Known Bugs :

NSOutlineView currently has a bug that causes it to send theoutlineView:validateDrop:proposedItem:proposedChildIndex:in situatuations where it is not necessary. In particular, if the mouse moved a bit, and the outline view determines the target it will suggest is the same as before, the method should not be sent. Currently, in this situation, the message will be sent, and clients should not count on this behaviour remaining.


NSImage

Two new methods have been added that allow an image to be rendered with any compositing operation and with any alpha value at the same time.
- (void)compositeToPoint:(NSPoint)point operation:(NSCompositingOperation)op fraction:(float)delta;
- (void)compositeToPoint:(NSPoint)point fromRect:(NSRect)rect operation:(NSCompositingOperation)op fraction:(float)delta;
Previously, an image could be composited with any operation but only at an alpha of 1.0 (-[NSImage compositeToPoint:operation:]) or just sourceOver with variable alpha (-[NSImage dissolveToPoint:fraction:]). Please note that there may be certain combinations of operation and alpha that cannot be printed correctly.


NSBitmapImageRep

NSImage via NSBitmapImageRep now uses the QuickTime GraphicsImporter to read additional bitmap image types. The additional types and extensions that QuickTime currently support are:

FlashPix: .fpix,.fpx
MacPaint: .pntg,.pnt,.mac
Photoshop: .psd
SGI: .sgi,.rgb
Targa: .targa,.tga
QuickTime Image Format: .qtif,.qti


NSOpenGLView

NSOpenGLView has been changed to archive information and allow dynamic changing of both the context and its associated pixel format. The new behavior is that the context isn't created until either -[NSOpenGLView openGLContext] or -[NSOpenGLView openGLContext] are called. This allow you to to change the pixel format after creating the view.New methods are:
+ (NSOpenGLPixelFormat *)defaultPixelFormat;
This class method is called when the context is created but no pixel format was specified. By default, this returns an format crated with an empty attribute list. You can override it in your custom class if you want to pass in a different set of attributes when the view is created.
- (void)clearGLContext;
This will dispose of the context associated with the view. You can use this to change the format and then calllockFocusagain to create a new context.
- (void)setPixelFormat:(NSOpenGLPixelFormat *)pixelFormat;
- (NSOpenGLPixelFormat *)pixelFormat;
These set and get the pixel format associated with the context. Setting the format after the context has been created has no effect on the view's current context. This information is archived.


NSOpenGLPixelFormat

NSOpenGLPixelFormat now follows the NSCoding protocol. Because the attribute list is an arbitrary list of integers, you must specify the list via an NSData object if the attributes are to archived. If you create the format using initWithAttributes:, then no data is archived and when it is restored, default to an old list. New methods:
- (id)initWithData:(NSData *)attribs;
This will save the attributes passed in an NSData.
- (NSData *)attributes;
- (void)setAttributes:(NSData *)attribs;
This will allow you to set and get the attribute list for the format object.


NSColor

A new class method has been added that returns a single color that reflects the tint of controls.
+ (NSColor *)colorForControlTint:(NSControlTint)controlTint;

Keyboard Focus

Because of pending changes to the appearance and behavior of the keyboard focus user interface, buttons, sliders, and tabs have been temporarily turned off for the Public Beta release. This means -[NSButtonCell acceptsFirstResponder], -[NSSliderCell acceptsFirstResponder], and -[NSTabView acceptsFirstResponder] now return NO. We intend to fix this for the next release.


Standard About Panel

Support for the deprecated NSBuildVersion, NSAppVersion, and NSHumanReadableShortName and the internal AuxiliaryInformation and BackgroundImage keys in the options dictionary has been removed.


Scripting

Scripting framework's dependencies on EOControl have been removed by copying key/value coding into Foundation, and by subclassing NSScriptClassDescription off of NSClassDescription in Foundation (instead of EOClassDescription).

After Public Beta we intend to fold Scripting and AppKitScripting into Foundation and AppKit, respectively. To protect your app from this change, it would be best to link against Cocoa.framework instead of AppKit.framework and AppKitScripting.framework.


NSRect vs CGRect

We intend to fold these two types into one. However, this has not happened for Public Beta. For situations where you need to pass these back and forth, we recommend you use a macro or inline function which basically does something like:
*(CGRect *)&nsRect
*(NSRect *)&cgRect

Alert panel

The human interface guidelines for alerts now state that the message of the alert appear at top (where the title is), and more optional secondary info appear beneath that, in smaller font. So, instead of
Close
Do you want to save this document before closing?
<Don't Save> <Cancel> <OK>
you should instead use something like:
Do you want to save this document before closing?
The contents of this document will be lost if it is not saved.
<Don't Save> <Cancel> <OK>
API for dealing with alerts, and the way we handle arguments, has not been changed (the "title" argument appears as the bold item, the "message" argument as the secondary info, and the optional arguments apply only to the message); in addition, a lot of the standard panels in AppKit and standard apps have also not been updated. Developers might want to change the arguments in their alert panel calls to be more in line with these new guidelines. For now, there is no convenient way to parameterize the first argument (with the %-replacements), but you can simply use [NSString stringWithFormat:] to get around this.


Java

The Java packages for Cocoa frameworks have been renamed from com.apple.yellow.* to com.apple.cocoa.*. Conversion tools and instructions can be found in /Developer/Java/Conversion/YellowToCocoa.


NSEvent

-characters and -charactersIgnoringModifiers methods now return values processed by the Carbon Text Services Manager. TSM maps key codes using the current keyboard script (i.e. you get 'w' for 'z' position if your current keyboard script is French). The mappings occur lazily so that NSEvent calls out and creates an NSString only when it is necessary. This NSEvent class change concludes the Carbon Text Services Manager integration in the kit.

The scrollWheel event is now sent to the view under the mouse rather than the first responder. This means by default the view under the mouse pointer is scrolled when the scrollwheel is used.


NSGlyphGenerator

The text system now uses ATS-based glyph generation. This means we use the same algorithm to generate glyphs as ATSUI does. All the default features in 'morf' or 'morx' table are applied automatically including ligature, propotional Hiragana/Katakana substitution, and Unicode precomposition. Among the features, only kLigaturesType is currently mapped to NSAttributedString attribute NSLigatureAttributeName. NSLigatureAttributeName value 0 applies kRequiredLigaturesOnSelector selector, value 1 does all default selectors, and value 2 does all selector supported by the font. The glyph generator still uses the rulebook-based glyph generation if the font has a corresponding rulebook. For the time being, you can force the kit to use CG-based glyph generation by setting the _NSForceRulebookGlyphGeneration to YES.

AppKit is disabling kDiacriticsType, kFractionsType, and kTypographicExtrasType/kSmartQuotesOffSelector even if it is enabled in the font.


NSPICTImageRep

If you render an NSPICTImageRep via its draw methods, it will be drawn using QuickDraw. Because f this, it will not be clipped or transformed based on the current NSView bounds and may end up drawing outside the view.

In the Public Beta, NSPICTImageReps are printed as bitmaps. The bitmap image is created with an off-screen image cache window so the image sent to CoreGraphics for printing is in 72 dpi and depending on the screen depth. This may result in less than optimal printing quality. This problem will be addressed in the future release.


Services

In Public Beta there is no "make_services;" instead service discovery is done by pbs at login time. So to get new services to be recognized you will need to log out and log back in.

There are some issues with discovery of services in the Public Beta. Services packaged as new-style bundles should not declare an NSExecutable key in their NSServices entry, as this prevents the service from working. This means the default executable in the package should be the one providing the service. Services bundled as old-style packages should not have a .service extension; instead, using the default .app is a workaround for this.



Notes specific to Mac OS X Developer Preview 4

Aqua

Aqua design metrics have changed since DP3. For the most part, UI elements are now the same size as their counterparts in Platinum (the Mac OS 9 look). Text in the user interface still uses Lucida Grande, but the size in most situations is now 13pt.

Use Interface Builder's "Apply Layout Guidelines" functionality to fix up the nibs.


NSTableView

In this release several new methods have been added to NSTableView.

Two methods support "indicator images" for use in table column headers. An arbitrary (small) image can be set to be rendered on the right side of the column header. (This is used for example in Mail to indicate the sorting direction of the currently sorted column in a mailbox.)
- (void)setIndicatorImage:(NSImage *)anImage inTableColumn:(NSTableColumn *)tc;
- (NSImage *)indicatorImageInTableColumn:(NSTableColumn *)tc;
Support has also been added for a highlightable column header, which can be used in conjunction with row selection to highlight a particular column of the table. (For example, as used in Mail to indicate the currently sorted column.)
- (void)setHighlightedTableColumn:(NSTableColumn *)tc;
- (NSTableColumn *)highlightedTableColumn;
Three new delegate methods have been added to help support the new indicator images and highlighted column headers. The first method is sent to the delegate whenever the mouse is clicked down in a column header. The second method is sent at the time the mouse subsequently goes up and the column has been "clicked" without having been dragged anywhere. The third method is sent at mouse-up time when the column has been dragged during the time the mouse was down.
- (void)tableView:(NSTableView *)tableView mouseDownInHeaderOfTableColumn:(NSTableColumn *)tableColumn;
- (void)tableView:(NSTableView *)tableView didClickTableColumn:(NSTableColumn *)tableColumn;
- (void)tableView:(NSTableView *)tableView didDragTableColumn:(NSTableColumn *)tableColumn;

NSApplication

The AppKit now handles "reopen" (rapp) AppleEvents. These events are sent whenever Finder reactivates an already running app because someone double-clicked it again or used the dock to activate it. By default the AppKit will handle this event by checking whether there are any visible NSWindows (not NSPanels) and, if there are none, it goes through the standard untitled document creation (the same as it does if the app is launched without any document to open). For most document-based apps, this means an untitled document will be created. The application delegate will also get a chance to respond to the normal untitled document delegations.

There is also a new NSApplication delegate method that apps can use if they want to have specific behavior for reopen that is different from the default behavior described above:
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag;
If you implement this method in your application delegate, it will be called before any of the default behavior happens. If you return YES, then NSApplication will go on to do its normal thing. If you return NO, then NSApplication will do nothing. So, you can either implement this, do nothing, and return NO if you do not want anything to happen at all (not recommended), or you can implement this, handle the event yourself in some custom way and return NO. The "flag" argument indicates whether NSApplication has found any visible NSWindows in your app. This flag can be used as an indication of whether NSApplication would do anything if you return YES.

Note that what happens to minimized windows is not determined yet, but the intent is that flag==NO indicates whether the AppKit will create a new window to satisfy the reopen event.


NSApplication now implements action methods to hide all applications (except the caller) and to unhide all applications (including the caller).
- (void)hideOtherApplications:(id)sender;
- (void)unhideAllApplications:(id)sender;
In DP4 unhideAllApplications will cause each application to order its windows to the front, which could obscure the currently active window in the active application.

Document modal API

The document modal API introduced in DP3 implies a nesting model that fails in the case of multiple windows presenting sheets. With that API, the caller expects to return from the call only after the modal session has been dismissed. However, this cannot be supported if the user wants to run multiple modal sessions and expects to dismiss the sessions in an arbitrary order.

DP4 introduces new API that returns immediately after beginning a modal session, then invokes a callback when the modal session is dismissed. The current document modal API will be deprecated, but will still work through DP4.

To start a document modal session, NSApplication.h:
- (void)beginSheet:(NSWindow *)sheet modalForWindow:(NSWindow *)docWindow modalDelegate:(id)modalDelegate didEndSelector:(SEL)didEndSelector contextInfo:(void *)contextInfo;
The didEndSelector method is optional. If it is implemented by the modalDelegate, this method is invoked after the modal session has ended and passed the code and the caller specified contextInfo. The didEndSelector should have the following signature:
- (void)didEndSheet:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
To end a document modal session, the sheet window must be specified:
- (void)endSheet:(NSWindow *)sheet;
- (void)endSheet:(NSWindow *)sheet returnCode:(int)code;
In NSPanel.h:
void NSBeginAlertSheet(NSString *title, NSString *defaultButton, NSString *alternateButton, NSString *otherButton, NSWindow *docWindow, id modalDelegate, SEL willEndSelector, SEL didEndSelector, void *contextInfo, NSString *msg, ...);
void NSBeginInformationalAlertSheet(NSString *title, NSString *defaultButton, NSString *alternateButton, NSString *otherButton, NSWindow *docWindow, id modalDelegate, SEL willEndSelector, SEL didEndSelector, void *contextInfo, NSString *msg, ...);
void NSBeginCriticalAlertSheet(NSString *title, NSString *defaultButton, NSString *alternateButton, NSString *otherButton, NSWindow *docWindow, id modalDelegate, SEL willEndSelector, SEL didEndSelector, void *contextInfo, NSString *msg, ...);
Note that the arguments are ordered differently than the NSRunAlertPanel() calls, in order to assure they are grouped better and provide better type checking of arguments.

Implementing the willEndSelector and didEndSelector method is optional. If willEndSelector is implemented by the modalDelegate, this method is invoked after the modal session has ended but before dismissing the sheet. The didEndSelector is invoked after dismissing the sheet. The willEndSelector and didEndSelector methods should have the following signatures:
- (void)willEndSheet:(NSWindow *)sheet returnCode:(int)code contextInfo:(void *)contextInfo;
- (void)didEndSheet:(NSWindow *)sheet returnCode:(int)code contextInfo:(void *)contextInfo;
In NSSavePanel.h:
- (void)beginSheetForDirectory:(NSString *)path file:(NSString *)name modalForWindow:(NSWindow *)docWindow modalDelegate:(id)delegate didEndSelector:(SEL)didEndSelector contextInfo:(void *)contextInfo;
Implementing the didEndSelector is optional. If didEndSelector is implemented by the modalDelegate, this method is invoked after the modal session has ended but before dismissing the save panel sheet. The didEndSelector method may dismiss the save panel itself; it will be dismissed on return from the method otherwise.
- (void)didEndSavePanel:(NSSavePanel *)savePanel returnCode:(int)code contextInfo:(void *)contextInfo;
For the next release we intend on putting doc modal sheet support into NSDocument.

NSEvent

A class method has been added to NSEvent.h to export the current mouse position, in screen coordinates:
+ (NSPoint)mouseLocation;
An event type, NSScrollWheel, has been added to NSEvent.h to support scroll-wheel events. In addition, the following method has been added to NSResponder.h:
- (void)scrollWheel:(NSEvent *)theEvent;
If an NSScrollView is the firstResponder, an NSScrollWheel event will be treated the same as a click on the scroller arrow.

NSEvent.h also defines methods to obtain the delta along each axis for a scroll wheel event:
- (float)deltaX;
- (float)deltaY;
- (float)deltaZ;

Support for dynamic screen changes

DP4 includes support for dynamic screen changes. If the user changes the screen resolution or size, the application delegate will be notified and windows will be repositioned if necessary to keep them on the visible screen and maintain their relative screen locations.

An application notification and delegate method have been added:
NSString *NSApplicationDidChangeScreenParametersNotification;
- (void)applicationDidChangeScreenParameters:(NSNotification *)notification;

NSDrawer

NSDrawers can now have delegates, with the following delegate and delegate notification methods:
@interface NSObject(NSDrawerNotifications)
- (void)drawerWillOpen:(NSNotification *)notification;
- (void)drawerDidOpen:(NSNotification *)notification;
- (void)drawerWillClose:(NSNotification *)notification;
- (void)drawerDidClose:(NSNotification *)notification;
@end
@interface NSObject(NSDrawerDelegate)
- (BOOL)drawerShouldOpen:(NSDrawer *)sender;
- (BOOL)drawerShouldClose:(NSDrawer *)sender;
- (NSSize)drawerWillResizeContents:(NSDrawer *)sender toSize:(NSSize)contentSize;
@end
The calls to the method drawerWillResizeContents:toSize: are not yet implemented. Additional methods on NSDrawer itself are:
- (void)setDelegate:(id)anObject;
- (id)delegate;
- (void)open:(id)sender;
- (void)close:(id)sender;

NSTabView

NSTabView has improved its support for truncation of its text label. When there is not enough space to display all of the NSTabViewItem's labels, truncation will be performed beginning first with longer labels. Note that, there have been subtle changes to the methods that subclasses of NSTabViewItem override to display their own label. Though the method signature remains the same, the usage has changed.
- (void)drawLabel:(BOOL)shouldTruncateLabel inRect:(NSRect)labelRect;
This method draws the tab label in labelRect, which is the area in between the curved end caps. shouldTruncateLabel is a hint that the label should be truncated; if shouldTruncateLabel is YES, then labelRect < ceil([... sizeOfLabel:YES])
- (NSSize)sizeOfLabel:(BOOL)flag;
This method returns the minimum or nominal size of the tab label. The flag indicates whether you should return the minimum or nominal label size. The returned value is used to compute the range of legal sizes for the tab label.


Loading NEXTSTEP 3.x .nib Files

The unarchiving mappings from old NEXTSTEP classes (like NXBrowser) to OPENSTEP classes (like NSBrowser) is now disabled by default. The temporary user default NSEnableNEXTSTEPArchiverMappings with a value of YES can be used to re-enable the installation of these mappings.

Note that the NXStringTable, NXBundle, StreamTable, and Storage classes have been removed from the ObjC runtime, so if the nib contains instances of these classes, it also will not load, and there is no way to correct that. For now, the List and HashTable classes, and the NXHashTable functions, remain, but you should anticipate these things being removed from the runtime in the future.

objc_getClasses

The objc_getClasses() function in objc/objc-runtime.h is obsolete. You should use the new objc_getClassList() function instead, as described in the comment in the header.

NSPDFImageRep

Support has been added to NSPDFImageRep to choose which page of a multipage document to render. Previously, only the first page was drawn.
- (void)setCurrentPage:(int)page;
- (int)currentPage;
- (int)pageCount;
The first two methods set and get the current page to display. The page index is zero based. pageCount returns the number of pages in the document. After calling setCurrentPage:, the rectangle returned by -[NSPDFImageRep bounds] is for the new page.

NSColor

A new method has been added to the list of system colors:
+ (NSColor*)windowBackgroundColor;
Under Aqua, this now returns an NSPatternColor that will draw the ruled lines for the window background.

controlColor has also been modified to return the same pattern since the most common usage for it is to draw the background of a non-rectangular but opaque control. If you use control color assuming that it is a solid, you may an incorrect appearance. You should use lightGrayColor in it's place.

A number of system colors, while still valid, are no longer meaningful under Aqua. These include any of the ones with 'control' in their name. They return the old Platinum appearance colors which are usually a shade of gray.

Dynamic system colors are no longer updated from defaults, except for those few (currently only two, the text selection color and control selection color) that are settable in the Preferences app.

NSWorkspace

A new method has been added that allows you to notify the Finder when a new file has been added.
- (void)noteFileSystemChanged:(NSString*)path;
NSDocument and NSSavePanel as been modified to use this method when saving a file. If you create a file directly, you should call this method so that the Finder can update the folder if it is open.

NSSavePanel

A new delegate method has been added to NSSavePanel that notifies the delegate when the save panel is about to expand or collapse. You may get a call to this the first time the panel is shown as it collapses or expands based on the last state it was in.
- (void)panel:(id)sender willExpand:(BOOL)expanding;
A new function that goes along with the new delegate method returns the current state of the save panel. Note that for the open panel, this currently always returns YES:
(BOOL)isExpanded;

NSOpenGLContext, NSOpenGLView

Support has been added for rendering OpenGL into a view in the AppKit. You can get direct access to the OpenGL system via NSOpenGLContext and its assocated NSOpenGLPixelFormat class or you can just create an instance of NSOpenGLView and when you lockFocus on the view, the current OpenGL context will be set to the view's. You cannot draw using regular 2D drawing in the view since it is completely covered by the 3D context.

NSOpenGLView has 2 public methods. One is an init method where you can pass in a custom pixel format to choose a specific set of features for rendering. If you just drag in an NSOpenGLView in InterfaceBuilder, it is equivalent to passing in nil for format in which case, the system will choose the best format it can based on the hardware capabilities.
- (id)initWithFrame:(NSRect)frameRect pixelFormat:(NSOpenGLPixelFormat*)format;
- (NSOpenGLContext*)openGLContext;
If you wish to draw to the view outside of a lockFocus call, you can simply set the current context directly via [[glView openGLContext] makeCurrentContext];.

For full screen or offscreen drawing, you will need to create your own NSOpenGLContext. Though NSOpenGLContext does allow you to associate any view with the context, you will have to handle any view frame changes yourself. It is recommended you use NSOpenGLView in these cases.

Defaults

The kit no longer registers several obsolete defaults, including NSHost and several for NSPrinter.

genstrings

genstrings now always writes out Unicode files. These can be edited in TextEdit or other text editors capable of dealing with Unicode.

For localizable strings with no table specified, genstrings would just write the output to stdout. It will now instead write the output to Localizable.strings, which is the default table consulted by the NSBundle/CFBundle code when no table is specified.

Standard About Panel

ProjectVersion and SystemVersionName keys are no longer looked for in the about panel options dictionary. These keys were not documented publically. The correct key to use is ApplicationVersion, which should have a value to indicate the product version name, for instance "Mac OS X" (for system apps), "Web Objects 4.5," "FooSimulator 2000," etc. If not specified in the options dictionary, the CFBundleShortVersionString key in from the bundle info plist will be picked up; if that is not there, the old form, NSAppVersion will be used. (Note that in DP4 there is a bug that prevents automatic picking up of the CFBundleShortVersionString string from Info.plist.)

For internal apps using the internal about panel function, this field is automatically populated with the product version name, "Mac OS X".

The Version key, if not specified, is now picked up from CFBundleVersion key in the bundle info plist. If that is not there, the old form, NSBuildVersion will also be looked for.

The InfoPlist.html release note has been updated with the other changes in Info.plist keys.

Text

Macintosh documents created with SimpleText (MacOS types TEXT, sEXT, ttro) can now be loaded into attributed strings when using initWithPath:documentAttributes: and initWithURL:documentAttributes:.

Embedded graphics are supported (such files are not directly creatable with SimpleText itself, but stored as PICT resources). Note that there are no plans for supporting saving of documents in SimpleText format.

In all methods taking a documentAttributes: parameter, if not NULL, on return it may now also contain the following additional keys:

@"DocumentType": NSString indicating how the document was interpreted; see NSAttributedString.h for possible values
@"CharacterEncoding": For plain text files only; NSNumber containing unsigned int specifying NSStringEncoding used to interpret the file

The following method has been added to NSMutableAttributedString as an general funnel point for all document loading:
- (BOOL)readFromURL:(NSURL *)url options:(NSDictionary *)options documentAttributes:(NSDictionary **)dict;
This method is like initWithURL:documentAttributes:; except it can be reused to reload the file into an existing attributed string, and the behavior can be customized with the options dictionary. If not NULL, this dictionary may contain the following values:

@"CharacterEncoding": For plain text documents; NSNumber containing unsigned int NSStringEncoding to be used if the encoding cannot be determined
@"BaseURL": For HTML documents; NSURL containing base URL
@"DefaultAttributes": NSDictionary containing attributes to be applied to plain files

NSLayoutManager

NSLayoutManager now include support for temporary attributes. These attributes are used only for on-screen drawing and are not persistent in any way. NSTextView uses them to color misspelled words when continuous spellchecking is enabled. Currently the only temporary attributes that will be recognized are those related to colors and underlines. The following temporary-attribute related methods are available for NSLayoutManager:
- (NSDictionary *)temporaryAttributesAtCharacterIndex:(unsigned)charIndex effectiveRange:(NSRangePointer)effectiveCharRange;
- (void)setTemporaryAttributes:(NSDictionary *)attrs forCharacterRange:(NSRange)charRange;
- (void)addTemporaryAttributes:(NSDictionary *)attrs forCharacterRange:(NSRange)charRange;
- (void)removeTemporaryAttribute:(NSString *)name forCharacterRange:(NSRange)charRange;

Linking Carbon.framework

AppKit.framework no longer links against Carbon.framework, but against subframeworks in there. It still brings in most of the frameworks covered by the umbrella framework; ones that are excluded include NavigationServices and CommonPanels. If your app pulls in Carbon symbols explicitly from these (and other not included frameworks) you should probably request to pull in Carbon.framework explicitly.

NSImage

[NSImage imageNamed:@"foo"] will now find foo.tiff in the localized resources directory (for the main language) before it finds some other type of foo in the non-localized directory. This behavior is changed in that before a non-localized "foo" (with a recognized image file extension) would be found before a localized "foo". This change was done for tiff only, for performance reasons.

NSPanel

NSPanel now has a special application activation behavior. NSPanel instances that satisfy the following conditions do not automatically activate their applications. This behavior makes developing accessory floating panel gadgets like input method palette panels easy.

Non-activating conditions:
1) It is an utility window
2) It is a floating panel
3) becomesKeyOnlyIfNeeded == YES
4) The mouse-down event occurs in a view that does not accept the first responder status

NSCell

The deprecated enum values NSStateMixed, NSStateOff, and NSStateOn have been removed from NSCell.h. Use NSMixedState, NSOffState, and NSOnState instead.

NSMenu

+(void)popUpContextMenu:(NSMenu*)menu withEvent:(NSEvent*)event forView:(NSView*)view;
This method will display an NSMenu as a context menu inside the view. Use this if the context menu support in NSView does not suit your needs. The menu will pop up positioned next to the cursor.

NSMatrix, NSTextField

The following methods have been made obsolete and removed from public headers. They are deprecated and an NSFormatter should be used instead to handle bad input.
- (SEL)errorAction;
- (void)setErrorAction:(SEL)aSelector;

NSMovieView

NSMovieView still not functional in Developer Release 4.

NSMenu

Images in popups and menus are still not working; this is a bug.

NSScreen

The following methods are private and should not be listed in NSScreen.h at all. They will be removed from the headers post-DP4:
- (NSRect)_savedVisibleFrame;
- (void)_saveVisibleFrame

Multiple Monitors

There are a number of known problems associated with rearranging the configuration of multiple monitors. Moving the menu bar to a secondary monitor is especially problematic. For DP4, we recommend that you leave the menu bar on the main monitor.

NSWindow

DP3 reentrancy problems with the NSWindow methods -[NSWindow setMiniwindowTitle:] and -[NSWindow setTitle:] have been fixed in DP4. These were due to dock interaction, which could cause runloop to be reentered.



Notes specific to Mac OS X Developer Preview 3

Aqua

The big change in Developer Preview 3 is Aqua, the new user interface. Aqua brings with it a lot of visual changes, new features, and many additions to the APIs.

Although you get the new look for Aqua automatically in your applications, some of the new features such as document modal panels are accessible via new APIs and are not automatically picked up.

For the most part, Aqua metrics are larger than those used previously (in the Mac OS X Server "platinum" look). This means that when pre-Aqua nib files are opened up under Aqua, certain controls will be clipped. In addition, Aqua introduces a new layout for the menu bar. See below for details on how to convert nibs to Aqua guidelines.


Platform-specific Resource Modifiers

In order to allow pre-Aqua and Aqua interfaces to co-exist, we have separate resource modifiers for the platinum appearance (used on Mac OS X Server) and Aqua. Use macintosh for the Mac OS X Server look, and macos for Aqua. You do this by appending "-macos" or "-macintosh" to the base name of any resource obtained (directly or indirectly) via NSBundle or CFBundle.

For those of you converting resources to support Aqua, but also needing to support the Mac OS X Server look, we suggest renaming your old resources to have the macintosh platform identifier, and saving you're the Aqua resources without a platform identifier. This is probably as simple as:
cp -r foo.nib foo-macintosh.nib
now edit foo.nib to for Aqua

(Things will get a bit trickier if you have other platform-specific resources.)

If you do not need to support Mac OS X Server, then you can simply have one set of nibs, with no special resource identifiers.


Converting UI to Aqua

Interface Builder provides a convenience for upgrading nibs to conform to Aqua guidelines. Open your nib files in IB, and use the "Apply UI Guidelines" menu command to fix up windows and menus.

"Apply UI Guidelines" applies only to the currently selected editing window; so if you have multiple windows in your nib, you will need to select each window by hand and perform this command. In addition, to fix up your menu layout, click on the menu editor (the on-screen representation of the menu, not the "MainMenu" image in the IB document window) and perform this command.

In many cases you might need additional tweaks to fix things up.

In old nib files, controls might not be using the "Message" font, but instead a hardwired font such as Helvetica. These are not automatically converted to use Lucida at 14 point, which is the new default font for most controls. In those cases it's best to set the font used by those controls to "User's Message Font," at 14 pt, selectable via the font panel in Interface Builder.


Drawer

Drawers are a new addition to the AppKit. For an example of a drawer, see the mailboxes drawer in Mail. From an API perspective, NSDrawer is a peer of NSWindow; like a window, a drawer is used to contain and display views. A drawer, however, can appear on screen only when associated with a window, which is called its parent. A drawer cannot be moved or ordered independently, but instead is attached to one of the edges of its parent, and moves along with it. Drawers may be resized, but a drawer can never be larger than its parent. A given window may have any number of drawers; it is the developer's responsibility to make sure that multiple drawers are not open at once overlapping each other on the same edge.

A drawer may be either open or closed, or in the process of opening or closing. When a drawer is closed, it does not appear on screen. A drawer may be opened on a particular edge of its parent; a drawer also has a preferred edge, which is used when it is told to open without an edge being specified. The opening or closing of a drawer does not happen instantaneously, so a notification is sent whenever a drawer has finished opening or closing. However, a drawer may be told to open or close at any time, with the expectation that the command will eventually be carried out. If a rapid series of open and close commands is issued, the last one may supersede the others, and in any case will determine what state the drawer finally ends up in.

The precise appearance of the drawer, and its implementation, may be platform-dependent. When a drawer is on screen, its views must necessarily be placed within some NSWindow so that they can be displayed, but this object is private and its precise class is likely to be platform-dependent. The NSDrawer API concentrates on the content area of the drawer rather than on its border or frame.

Methods are available to create a drawer, to supply it with a content view and a preferred edge, and to associate it with a parent:
- (id)initWithContentSize:(NSSize)contentSize preferredEdge:(NSRectEdge)edge;
- (void)setParentWindow:(NSWindow *)parent;
- (NSWindow *)parentWindow;
- (void)setContentView:(NSView *)aView;
- (NSView *)contentView;
- (void)setPreferredEdge:(NSRectEdge)edge;
- (NSRectEdge)preferredEdge;
Note that the parent window will retain the drawer, and not vice versa. A drawer may be disassociated from any parent by setting its parent window to nil, but in that case the drawer would need to be explicitly retained if it is still needed. Also, a drawer without a parent cannot be opened. If setParentWindow: is sent to a drawer that is not closed, the change will take effect only when the drawer is next closed.

Methods are also provided to open or close a drawer, and to ascertain its state:
- (void)open;
- (void)openOnEdge:(NSRectEdge)edge;
- (void)close;
- (NSDrawerState)state;
- (NSRectEdge)edge;
Methods are provided to set the size of a drawer, or to set minimum and maximum sizes for it, but these do not override the rule that a drawer cannot be larger than its parent.
- (void)setContentSize:(NSSize)size;
- (NSSize)contentSize;
- (void)setMinContentSize:(NSSize)size;
- (NSSize)minContentSize;
- (void)setMaxContentSize:(NSSize)size;
- (NSSize)maxContentSize;
An open drawer is attached precisely to the appropriate edge of its parent window, but its position and size along that edge may be controlled, relative to the content area of its parent, with a leading and trailing offset. If these parameters are not set, default values will be supplied that are appropriate for the current interface style. These offsets may not be negative.
- (void)setLeadingOffset:(float)offset;
- (float)leadingOffset;
- (void)setTrailingOffset:(float)offset;
- (float)trailingOffset;

Font Panel

The Font Panel user interface has been considerably enhanced in this release. The panel now has three panes (Fonts, Favorites, Edit Collections).

The main view of the panel is now a three-column browser, with the left-most column being a list of named font collections. The other two columns are the familiar family and typeface columns. The size scrolling list is unchanged. Selecting an element in this browser now causes immediate update of whatever portions of the document are selected, as well as update of the preview area. Prior releases required the user to hit a button to set the document's font.

The Edit Collections view allows the user to select a collection, view its members, and add or remove members with the << and >> buttons. Users can also create new collections or delete existing collections.

The Favorites view is simply a list of fonts that can be set with one click, including their size. Names of favorite entries are given descriptive default names, but can be edited by the user.

The accessory view, if used, appears at the very bottom of the panel, below the buttons, instead of being embedded within the panel above the buttons.

There is a new method reloadDefaultFontFamilies in the font panel. This is a "trigger" method intended only for use by delegates. It causes the font panel to reload the set of default font families. When the re-load operation occurs, the delegate will be called for each family, as documented, and have the opportunity of deciding whether the family should be included or not. This is intended to fix the problem that one cannot set the delegate of a font panel without having instantiated it, so at the time of original instantiation, the delegate has no chance to examine the families.


Application

The NSApplicationDidFinishLaunchingNotification is now sent at a slightly different time. Handling of opening or printing files or of opening an untitled document during application launching used to be handled prior to the main event loop starting up. Because the AppleEvents for 'oapp', 'odoc', and 'pdoc' are received through the main event loop as the first event when an application starts running, if we send the NSApplicationDidFinishLaunchingNotification right before entering the main event loop, that notification will happen before documents are opened. To avoid this, the notification is now sent immediately after handling the 'oapp', 'odoc', or 'pdoc' event during the first pass through the loop.

This change should actually preserve what most observers of this notification expect: it will still be sent after the application has finished launching and opened any initial documents. But it is now sent after the run loop has been cycled once and the first event (the launch-time AppleEvent) has been handled.


Document Modal Panels

Mac OS X introduces the concept of document modal panels ("sheets"). A document modal panel causes the document to which it refers to enter a modal state, without putting the entire application into a modal state. The document modal panel is referred to as a sheet and has a special appearance and behaves as if it were attached to the document window. API has been added to support creation of document modal panels.

If the position of the document window at sheet creation time would cause the sheet to be partially offscreen, the parent is moved on screen in order to fully display the sheet. When the sheet is dismissed, the parent is moved back to its original position.


SavePanel

There is a new method that allows the save panel to be presented as a sheet.

Note that if your pre-Aqua default save panel size was very small, there may be problem with the initial layout of some items in the panel. You can remove the old saved default size by typing the following in Terminal to reset to the initial default size:
defaults delete NSGlobalDomain "NSWindow Frame NXSavePanel"

Menu

The implementation of menus has changed drastically; NSMenuView and NSMenuItemCell are no longer used,-[NSMenu menuRepresentation]now returns nil, and tear off menus are no longer available. For Developer Preview 3, there is no support for menu item images. If there is no text in the menu item, a placeholder text consisting of "<image>" or "<image name>" will be inserted instead. Menu item state images are not supported either and in their place the standard checkbox or dash for on and mixed states are used.


Dock Miniaturization

On Mac OS X, miniaturizing a window causes a thumbnail of the window to appear in the dock. Calling -[NSWindow miniaturize:] will cause the target window to animate (genie) into a thumbnail, and -[NSWindow deminiaturize:] will re-expand the window. The title of the thumbnail should be brief, and is set by calling -[NSWindow setMiniwindowTitle:]. If the thumbnail has not been named via setMiniwindowTitle:, an abbreviation of the window title will be used.

In DP3, operations involving the dock may cause the runloop to be reentered in ways your application does not expect (for example, timers might fire). These operations include -[NSWindow setMiniwindowTitle:], -[NSWindow setTitle:] (if you do not explicitly call setMiniwindowTitle:), -[NSWindow miniaturize:], and -[NSWindow deminiaturize:]. We will be looking at ways to prevent this reentrancy in the future, but for now you may need to safeguard against it.


Continuous Spelling Checks

There are three new methods in NSTextView.h:
- (void)setContinuousSpellCheckingEnabled:(BOOL)flag;
- (BOOL)isContinuousSpellCheckingEnabled;
- (void)toggleContinuousSpellChecking:(id)sender;
These turn on and off continuous (as-you-type) spellchecking. In addition, NSTextView's context menu will allow you to correct a selected misspelled word. There is also a new method in NSSpellChecker.h:
- (NSArray *)guessesForWord:(NSString *)word;
This allows programmatic access to the list of suggested corrections for a given word.


Box

There is a new NSBoxType that overrides the existing border types.
typedef enum {
NSBoxPrimary= 0,// default
NSBoxSecondary = 1,
NSBoxSeparator = 2,
NSBoxOldStyle = 3 // use border type
} NSBoxType;
By default, a new NSBox has a box type of NSBoxPrimary. If the box type is NSBoxSeparator, then a separator line is drawn centered in the box parellel to the longest side. If the box style is NSBoxOldStyle, then the border type is used instead. In all cases, if the border type is NSNoBorder, no box is drawn.
- (void)setBoxType:(NSBoxType)boxType;
- (NSBoxType)boxType;

Window

There is new API to turn shadows on and off on a per window basis:
- (void)setHasShadow:(BOOL)hasShadow;
- (BOOL)hasShadow;
Changing the shadow state affects the window immediately. You can also override hasShadow. The default is that all windows except borderless ones have a shadow.


Pattern Color

NSColor now contains support for patterned colors made from NSImages:
+ (NSColor *)colorWithPatternImage:(NSImage*)image;
- (NSImage *)patternImage;
The NSImage is retained by the pattern color.

There is also a new color space, NSPatternColorSpace, to go along with this feature.

The pattern is always aligned to the bottom of the window. Use the CoreGraphics call CGSetHalftonePhase() to change the phase of the pattern.

System NSColors do not yet support the patterns used by Aqua. However, a new function has been added to draw the Aqua window background pattern. You can use this for custom controls so that the control doesn't need to be transparent:

void NSDrawWindowBackground(NSRect aRect);

This assumes the current view is in a window and adjusts the pattern so that it is always aligned with the top of the window.


Control Tints

You can specify whether NSCell, NSTabView, and NSScroller have a tinted or clear appearance when the window is active. The currently valid tints defined in NSCell.h are:
typedef enum _NSControlTint {
NSDefaultControlTint = 0,// system 'default'
NSClearControlTint = 7
} NSControlTint;
The new methods in these three classes are:
- (void) setControlTint:(NSControlTint)controlTint;
- (NSControlTint)controlTint;

Autoscroll while dragging

NSClipView now implements autoscrolling while dragging. Autoscrolling starts when the cursor is held within 5 pixels from the edges for 0.3 seconds.


SplitView

The appearance of NSSplitView has changed; horizontal splits are drawn transparent with a two-line grabber in the center. Vertical splits currently are drawn completely transparent; this is expected to change before the final release of MacOS X. In addition, there is new API on NSSplitView to change a horizontal split view's appearance from the transparent version seen in the Font Panel to the bubbled, opaque one seen in Mail. The new methods are -setIsPaneSplitter: and -isPaneSplitter; the bubbled, opaque appearance is the pane splitter appearance (i.e. the split view used by Mail returns YES from isPaneSplitter).

Interface Builder allows you to choose between the two splitter types through the split view inspector.

Split views also now dynamically resize their subviews as the thumb is dragged. One side effect of this is that NSSplitView's delegate methods and notifications pertaining to resizing are sent much more often as the drag is performed. This could result in a noticeable performance impact if the methods or notifications cause time-intensive routines to be called.


NSUserInterfaceValidation

This new protocol defines the generic and standard user interface validation mechanism. Currently NSMenuItem is the only client of this protocol. Please refer to comments in NSUserInterfaceValidation.h for details.


Document

A new method called noteNewRecentDocument: has been added to NSDocumentController. This method is similar to noteNewRecentDocumentURL: except that the NSDocument instance is passed to it. The default implementation gets the URL from the document and calls noteNewRecentDocumentURL:. This new method is always invoked by NSDocument instead of noteNewRecentDocumentURL: and it has been added to provide a better override point for NSDocument based apps that wish to have a chance to leave some documents out of the recents list. Making this decision based on the NSDocument instance is often more convenient than having to base it on the URL.

Non NSDocument-based apps can and should still call noteNewRecentDocumentURL: to get the recent documents feature for their applications.


BezierPath

NSBezierPath methods appendBezierPathWithPackedGlyphs: and drawPackedGlyphs:atPoint: are now implemented.


String Drawing

NSParagraphStyleAttributeName now does the correct thing regardless of flippedness of the focused view.


StatusBar

Because of UI changes, status bar items are no longer drawn on the screen in Developer Preview 3 even though the API has not changed. A replacement will be made available in a subsequent release.


TableView

Because of additional drawing required, the clip view that contains the contents of a table view has it's copiesOnScroll flag set toNOat this time. This may affect scrolling performance for large table views.



Notes specific to Mac OS X Developer Preview 2

Cocoa Framework

DP2 includes the concept of "umbrella frameworks," a small number of public frameworks which simply link against other frameworks. The idea is for applications to link against these umbrella frameworks rather than their individual components, which will make it easier for the underlying list of implementation frameworks to be changed.

One of these umbrella frameworks is Cocoa.framework, which currently includes AppKit and Foundation, but in the future will be expanded to include the scripting frameworks.

Other umbrella frameworks are Carbon, ApplicationServices (common UI level services), CoreServices (CoreFoundation, CarbonCore, and other UI-free common services), and System (Posix, BSD, and Mach APIs).


Application Packaging

The new application package structure is outlined in the CFBundle/CFPlugIn release notes. The old structure will continue to work, but it is recommended that you convert your application to the new structure as it is the format NSBundle first checks for when looking for resources.

In DP2, on "make install," the Project Builder makefiles will still create an old-style package. However, you can add the following to your Makefile.preamble to cause the new style package to be built:
BUNDLE_STYLE = MACOSX
This will cause the script /System/Developer/Makefiles/pb_makefiles/convertBundle to be run at the end of "make install" to convert your application's app package to the new style. Note that if you run "make install" as yourself and not as root, this script might fail.

If your application package needs to work on MacOS X Server, or you have some code that rummages through the application wrapper without going through NSBundle or CFBundle APIs, you might not be able to switch to the new format immediately.


Application and Document Icons

In DP2, Finder expects application and document icons in the ICNS format. TIFF does not work. The following describes the steps needed to create ICNS versions of your icons and get them incorporated into your project.

Note that you need to do this only for the icons displayed by Finder. Most of the TIFF images in your application do not need to be converted.

You can use the tool /usr/bin/tiff2icns to convert your TIFF icons to ICNS format. ICNS, like TIFF, supports multiple formats in one file, and the conversion should preserve all the images in the TIFF, in addition to creating a 1-bit hit mask that the Finder requires.

The tool will reduce the 48 x 48 image in the TIFF to 32 x 32 if the TIFF doesn't have a 32 x 32 format. If the TIFF has a 16 x 16 image, and it's deeper than the 48 x 48, the tool might choose to expand that one instead. If you notice that the 32 x 32 image in the ICNS is blurry (which will be the case if it was scaled from the 16 x 16), you might want to extract the 48 x 48 icon into its own TIFF file and then do the conversion. You can use "tiffutil -info" to enumerate the images in the TIFF and "tiffutil -extract" to extract the correct one.

Once you have your ICNS files, add them to your app project as non-localizable (or localizable, if they need to be localized) resources. Then, in ProjectBuilder's project inspector, go to the "Project Attributes" panel. Delete all of the extension / icon name pairs as these are not used anymore. Do not delete the entry for "App Icon"; this image is still used by [NSImage imageNamed:@"NSApplicationIcon"] as the icon for your application within your application.

Finally, you need to add some new keys to your CustomInfo.plist file. If you don't already have a CustomInfo.plist file, you will need to create one (in the "Supporting Files" bucket).

For your application icon, simply include an entry for CFBundleIconFile. For each document type the app supports, include an entry in the array CFBundleDocumentTypes. If your app supports no documents, put an empty array here.

You can look at TextEdit's CustomInfo.plist file (/System/Developer/Examples/AppKit/TextEdit/CustomInfo.plist) as a sample. TextEdit declares four document types; 3 of which it can edit, one of which (html) it can just view.

The InfoPlist release note has more details on the various keys and their values.


InterfaceBuilder

IB now supports NSTableView and NSOutlineView. Please refer to InterfaceBuilder release notes for more info.


Document / DocumentController

It is now easier to subclass NSDocumentController by instantiating a subclass in your main nib. Interface Builder has certain problems in test interface mode if you use such a subclass, but they are cosmetic.

NSDocument's -readFromFile: now resolves symlinks in the filename.

A couple new methods that allow more advanced access to the saving facility to allow access to the original backed up document and control over the actual backup process have been added.

NSWindowController is now a subclass of NSResponder. This is a binary and source compatible change for both Objective-C and Java. In addition, and NSWindowController automatically installs itself as the -nextResponder of its window. What this means is that an NSWindowController subclass can implement responder methods like keyDown: and receive them as any responder in the chain normally would.


Recent Documents

Support for an "Open Recent" menu has been added. NSDocument based apps will get this new menu automatically. Non-NSDocument apps will have to add this menu and call NSDocumentController's noteNewRecentDocumentURL: method to get items to appear in it.


QuickDrawView

A new flipped, non-opaque view has been added to Cocoa that will allow you to draw using Carbon QuickDraw. Whenever a lockFocus call on the view is made (such as just before -[NSQuickDrawView drawRect:]), a QuickDraw CGrafPort will have been created and set. The port frame reflects the visible bounds of the view and may change between calls. You can get the view's CGrafPtr by calling -[NSQuickDrawView qdPort] though it is only valid when inside a lockFocus/unlockFocus. Also note that it creates a CGrafPort for each view.


ToolTips

NSView is now capable of more sophisticated tooltip control, introduced with the following three methods:
- (NSToolTipTag)addToolTipRect:(NSRect)aRect owner:(id)anObject userData:(void *)data;
- (void)removeToolTip:(NSToolTipTag)tag;
- (void)removeAllToolTips;
If NSView detects that a tooltip rectangle has been activated, it sends the owner the following method to obtain the string to display:
- (NSString *)view:(NSView *)view
stringForToolTip:(NSToolTipTag)tag
point:(NSPoint)point
userData:(void *)data;
In addition NSMatrix now supports per-cell tooltips:
- (void)setToolTip:(NSString *)str forCell:(NSCell *)cell;
- (NSString *)toolTipForCell:(NSCell *)cell;

TableView

A new method, dataCellForRow:, has been added to NSTableColumn to manage the cell used to draw the actual values in a table view. NSTableView now always calls dataCellForRow:, which, by default just calls the method dataCell. Subclassers can override this if they need to potentially use different cells for different rows. Subclassers should be prepared to handle row == -1 in cases where no actual row is involved but the table view needs to get some generic cell info.


Carbon

All Cocoa applications now bring in the Carbon libraries, which means that the public symbols in these libraries appear in the same name space as the application. Most of the public symbols in Carbon do not use prefixes, which makes it possible for there to be symbol conflicts. The solution to this is to avoid the conflicts by renaming your symbols.


Performance

Because of large underlying changes in the system since MacOS X Server, it is possible that some performance problems have been introduced into your application. Most of these are in the underlying libraries and system, and will be addressed for the final release. (Examples of this include excessive memory allocation and initialization of libraries and resources during launch.). However, the way your application does things (look for resources, traverse the file system, etc) might also be causing some additional problems that might be easy to pinpoint and remedy. You can use Sampler, MallocDebug, or other tools to check for problems.


Services

Services, which were mostly broken in DP1, now work.


GraphicsContext

NSGraphicsContext now has methods to save/restore the current graphics state on a per-thread basis.


ClipView and ScrollView

NSClipView and NSScrollView both support the ability to provide a see-through background (as in the standard about box) via the new setDrawsBackground: method.


Pasteboard

The format for property lists on the pasteboard has changed again; this might break code which makes assumptions about this format. For instance, code which reads an NSString from the pasteboard using dataForType: and attempts to deserialize it by hand is now broken. See DP1 notes (below) for more details.


Window Ordering and Activation

NSWindow no longer activates the main window when the key window closes if the main window is not at the top of the app's window z-order. The next window in the z-order which is willing to be key is activated. Most people should not notice any difference.

In addition, a number of window ordering and application activation bugs have been fixed. For one, dragging an item from an application window will no longer bring the application forward. The document drag button has also been fixed so selecting it does not bring its window forward.

However, some activation issues still remain. For instance, when windows are brought up in an application that is not key, they usually come up behind the other windows in the app.


StatusBar

Status bar items with menus that have submenus now work correctly (ie the submenus will appear and track properly).


Sound

In DP2, NSSound can now play uncompressed AIFF sound files as well as uncompressed sounds in NeXT/AU and WAV formats.

In Mac OS X Server, NSSound used to be able to play compressed NeXT-style sound files; these are no longer supported.


Text

NSTextView was caching typing attributes from the previous backing store when it got hooked up to a new backing store. This has been fixed.

NSTextStorage now has the ability to fix attributes lazily; three new methods have been added to support this feature.

The method fixesAttributesLazily should be overridden in concrete subclasses which can do this to return YES. In the abstract NSTextStorage superclass this method returns NO; but the default concrete NSTextStorage subclass returns YES.

processEditing now calls invalidateAttributesInRange:. If the text storage is not lazy this just calls fixAttributesInRange:, causing things to happen as before. If the text storage is lazy this instead just records the range needing fixing.

ensureAttributesAreFixedInRange: should be called in a text storage which is lazy to ensure the attributes are fixed in a certain range. NSTextStorage subclasses that wish to support laziness must call it from all attribute accessors that they implement. The default concrete subclass of NSTextStorage calls this from its accessors to ensure clients always see a consistent view of the attributes.


RTF

The RTF reader now supports MacOS encoding values for \fcharsetN. It can now read any encoding supported in RTF1.5. Tested against AppleWorks, Word97 on NT, Word98 on MacOS, WordPad on NT, MacOS X Server, and OPENSTEP 4.2 generated RTF files containing Latin1 & Japanese chars. Also, the RTF reader now supports the RTF1.5 Unicode string directives \uN and \ucN.

The RTF writer now uses very similar encoding scheme to Word9x. It encodes in font encoding, that provides maximum compatibility with other RTF readers. As the result, it encodes latin1 characters in MacOSRoman on MacOS and WindowsLatin1 on Windows.

This change makes RTF files generated on MacOS incompatible with OPENSTEP 4.x where non-ASCII characters are involved since there was no MacOSRoman decoder on the OS. You can force the reader to generate in Microsoft encodings by setting NSRTFWriteOpenStepCompatibleEncodings default value to YES.

With NSRTFWriteOpenStepCompatibleEncodings == NO (default), generated files with Latin 1 characters were successfully loaded into Apple Works, Word97 on NT, Word98 on MacOS, and TextEdit on MacOS X Server. Unfortunately RTF files with Japanese do not load correctly in TextEdit on MacOS X Server, which did not recognize the Japanese charset indicator.

With NSRTFWriteOpenStepCompatibleEncodings == YES, the generated files were successfully read by TextEdit on MacOS X Server, WordPad on NT, and TextEdit on OPENSTEP 4.2, in addition to the above.


Dragging

Cocoa, Carbon, and Classic are all moving towards a common layer for dragging, and in DP2 dragging a single file between Cocoa and Carbon works. However, there are still some bugs.

Dragging to and from a local pasteboard does not work. The NSDraggingInfo protocol method -draggingPasteboard will always return the pasteboard named NSDragPboard, so the destination will not find an alternate pasteboard used by the source.

The NSDraggingInfo protocol method draggedImageLocation will reflect the offset of the image from the current mouse location only if the source and destination of the drag are the same application. If the drag is from one application to another, draggedImageLocation will return the current mouse location, ignoring any image offset.


Aborting a modal session

In order to stop a modal session from an NSTimer or delayed performer, you must call -[NSApplication abortModal]. -[NSApplication abortModal] now sends an NSAppKitDefined event to the application rather than raising an NSException, and it will return to the caller.


MovieView

NSMovieView does not work in DP2.


ScrollView

Holding down the up/down buttons on a scroller causes the scrolling speed to increase over time by increasing the number of lines that are scrolled at a time. This should not cause any incompatibilities.

By default scroller buttons are now separate; you can set the NSScrollerHasSeparateArrows default to NO if you want your arrows together.


Printing & View Print API

Printing support in AppKit has gone through massive changes. The printing machinery is now hooked into the Tioga print manager; NSPrintPanel and NSPageLayout use Carbon implementations provided by Tioga; and NSView's print related API is simplified because that the original design was aiming to support Adobe's Document Structuring Convention.

NSView now has PDF generation capability via the following methods, which work just as their EPS counterparts:
- (void)writePDFInsideRect:(NSRect)rect toPasteboard:(NSPasteboard *)pb;
- (NSData *)dataWithPDFInsideRect:(NSRect)rect;
Instead of multiple entry points that had been required to support Adobe DSC, NSView now receives only the following five messages during print operation:
- (NSString *)printJobTitle;
- (void)beginDocument;
- (void)endDocument;
- (void)beginPageInRect:(NSRect)r atPlacement:(NSPoint)loc;
- (void)endPage;
Because NSPrintPanel and NSPageLayout use Carbon panels, all the instance variables declared for the classes are never initialized and applications should not access any of the variables.


StringDrawing

drawInRect: variants of NSStringDrawing API now correctly provide clipping, and the drawing appears at the right place regardless of flipped-ness of the focused view.


Box, ScrollView, and ClipView

Sending removeFromSuperview message to the content/document view of NSBox, NSScrollView, and NSClipView will correctly clear their corresponding ivars.
NSBox *myBox;
NSBox *srcBox1;
NSBox *srcBox2;
[myBox setContentView:myViewIsInBox1 ? [srcBox1 contentView] : [srcBox2 contentView]];
The above example worked since srcBox1 and srcBox2 always had the pointer to their content views untouched by -removeFromSuperview method called by the invocation of -setContentView: with myBox. Now, -contentView method returns nil for the second time the above code was executed since content view pointers in both srcBox are cleared by setContentView:.


Menu

After Preview Release 2, the implementation of NSMenu and NSMenuItem will change to sit on top of the Carbon Menu Manager similar to the Windows implementation of Cocoa menus. This means you should not assume that there is an NSMenuView or NSMenuItemCell behind an NSMenu or NSMenuItem respectively. Images set using -[NSMenuItem setOnStateImage], -[NSMenuItem setOffStateImage], and -[NSMenuItem setMixedStateImage] will still be supported as will setting the font for popup menu buttons.


Fonts

Cocoa and Carbon do not currently use the same set of fonts as CoreGraphics and QuickDraw do not yet use the same underlying library for text rendering. This will be remedied soon.

Please refer to DP1 notes for Font (below) to get new fonts to appear in Cocoa applications for testing purposes.


Removed Defaults

Some defaults that are no longer necessary were removed, along with support for registering them in the default domain:

- Fax related defaults
- NSCachedColorConversion (used to be YES; now this always happens)
- NSDrawUsingGradients (used to be NO)
- NSObjectLinkUpdateMode (used to be 2)
- NSMiniaturizeAnimationRate (used to be blank)
- NSPSName (used to be blank)
- NSMenuX, NSMenuY (0.0, 1000000.0)



Notes specific to Mac OS X Developer Preview 1

The AppKit includes the following new features and changes since MacOS X Server. In some cases the notes below might be invalidated by changes in MacOS X Developer Preview 2, listed above. Also note that for notes pertaining to DP1 and earlier, we use the term "Yellow Box" to refer to Cocoa.


Graphics

MacOS X does not include Display PostScript; instead, graphics functionality for Yellow applications is provided through a new client-side framework named CoreGraphics.

One implication of this is that PostScript functions, and code generated using pswrap will no longer work. In the Developer Preview Release, some PSxxx() functions are still supported for binary compatibility, but their use in new code is highly discouraged since their functionality may not be exactly emulated on top of CoreGraphics and they will be removed in a future release. Instead use NSBezierPath or various other drawing classes in AppKit, or functions declared in NSGraphics.h, or CoreGraphics API directly.

The following functions have been added to NSGraphics.h. They should be used in place of PScompositerect():
void NSRectFillUsingOperation(NSRect aRect, NSCompositingOperation op);
void NSRectFillListUsingOperation(const NSRect *rects, int count, NSCompositingOperation op);
void NSRectFillListWithColorsUsingOperation(const NSRect *rects, NSColor **colors, int num, NSCompositingOperation op);
They are equivalent to the non-NSCompositingOperation versions except that they set the compositing operation before filling the rectangles. All compositing modes except NSCompositeHighlight are supported.

The following functions are currently no-ops:

NSDottedFrameRect

The following functions should no longer be used and may return dummy values:

NSHighlightRect, NSCopyBitmapFromGState, NSGetWindowServerMemory

The compositing mode NSCompositeHighlight is no longer supported for any function. Using it for a drawing operation will result in the use of NSCompositeSourceOver instead.

CoreGraphics currently does all drawing in an anti-aliased mode. This has some impact; for instance, code which "erases" drawing by redrawing using a different color might no longer erase every pixel. Images displayed at non-integral boundaries might end up being anti-aliased.

Text is also anti-aliased above a certain point size (currently 16pt). In the Developer Preview release, this value can be tweaked with a user default (see Font discussion below).

Zero-width lines currently do not draw anything. In PostScript this used to draw the thinnest possible line for the device.

Finally, the "-NSHost" command-line option is no longer supported.


DPSContext

Before MacOS X, there was a NSDPSContext object that wrapped a DPSContext handle which, in turn, represented both the application's connection to WindowServer and the graphics context. An NSDPSContext object was instantiated by the framework automatically at application launch time, and you only had to deal with the instance except in certain situations (i.e. your application was multi threaded, or explicitly dealing with a print operation). The "current" NSDPSContext was pretty predictable since the instance that was created at launch time was always current and active, unless your app was in the middle of printing. That is not true in MacOS X, for one thing, NSDPSContext has been removed. (Unfortunately the header files were still left in the release, but they should not be imported. They are not imported automatically by AppKit.h anymore.)

AppKit now only exposes an abstract superclass NSGraphicsContext that is automatically instantiated for each NSWindow. Also, NSWindow instantiates additional NSGraphicsContext objects for each drawing secondary threads as needed. NSView's lockFocus method sets its window's graphics context current, in addition to setting the current coordinate system and clipping state.

Most operations on NSDPSContext are now either not necessary or should be performed on NSGraphicsContext.

For the most part, the principle of implementing the drawRect: method is still the same. By the time your custom NSView class receives drawRect:, the framework has already set up the drawing context for you. You only need to call your drawing functions in the method, and the framework makes sure your drawing appears in the desired view. You can either use AppKit's own drawing API (NSBezierPath, NSImage, and NSString's drawing methods) or call CoreGraphics functions directly. You can query the CGSContextRef handle for the current graphics context by [[NSGraphicsContext currentContext] graphicsPort]. Your drawRect: method would like:
- (void)drawRect:(NSRect)rect {
CGSContextRef cgContext = [[NSGraphicsContext currentContext] graphicsPort];
// Construct path (line from 10.0/10.0 to 100.0/100.0
CGMoveTo(cgContext, 10.0, 10.0);
CGLineTo(cgContext, 100.0, 100.0);
// Set stroke color to white
CGSetGrayStrokeColor (cgContext, 1.0, 1.0);
// Stroke
CGStroke (cgContext);
}
As you have seen so far, the basic drawing principle remains the same. The lockFocus/unlockFocus method pair sets up the drawing environment, and you call drawing functions. But, the underlying meaning of the current graphics context is changed. The difference is entirely contained in the lockFocus method. The lockFocus method now performs the following operations:

1) Calls +[NSGraphicsContext setCurrentContext:] with the context for the view's window. It creates a new context for subthreads if they don't have one yet.

2) Saves current graphics state by calling -[NSGraphicsContext saveGraphicsState]. Note that PSgstate used to save the current window device, but the saveGraphicsState method does not, since each NSGraphicsContext object has no knowledge of contexts for other windows.

3) Sets up the coordinate system and clipping state by calling CoreGraphics functions.

Note that while it used to work, generally, to call currentContext or saveGraphicsState outside of a focused situation, this is no longer necessarily the case.


Image

Several bugs with GIF and JPEG handling have been fixed.

8-bit indexed TIFFs do not work in this release; you will need to convert them to RGB before using them.


Font

PostScript fonts are not supported in the Developer Preview, and API specific to them is no longer available (details below). The only font file format currently supported is the ".TTF" file.

Formerly, fonts were found in /System/Library/Fonts and other locations. These locations are not searched in this release. Family and face information relevant to the NSFontPanel is still stored in /System/Library/Fonts/.default.fcache, but the directory is otherwise empty.

End-user fonts and application-installed fonts are not supported in this release. The CoreGraphics framework looks for TrueType fonts only in one location, /System/Library/Frameworks/CoreGraphics.frameworks/Resources.

Developers should not use this location for fonts unless absolutely necessary for software development. In future releases, other locations for third-party fonts will be supported.

Formerly, font metric data was shared among processes and vended by the Pasteboard Server (pbs). In the current implementation, this data is no longer shared, but the information is produced on demand and a copy is kept in each application as needed. This situation will be remedied in the future, since it will be necessary to have shared data again for large font support (e.g., glyph bounding rectangles in Chinese fonts).

The NSText system uses the bounding rectangle of fonts to determine the default line height. In the future, this is likely to change. One effect of using the bounding rectangle is that in this release, all of the line heights have potentially changed from what they were when rendered with PostScript fonts. This affects some NIB files that use fixed-height multi-line text fields: lines near the bottom of the field may be partially clipped. The line heights in the current set of system fonts are sometimes slightly taller than in the PostScript fonts with the same names, due to the fonts' differing glyph complements. The difference is particularly noticeable with the Helvetica family. Developers may wish to check their NIB files for fixed-height multi-line text fields and re-size them with the new fonts if appropriate.

The method afmDictionary is being made obsolete. In this release, it returns nil.

The method afmFileContents is obsolete and no longer implemented.

The obsolete widths method is no longer implemented. Formerly, this method returned an array of 256 floats and was only useful with "base" fonts. It has been deprecated for several years.

The method fontWithName:matrix:, while still supported, does not work in exactly the same manner as in the past. The usage of font and text matrices in CoreGraphics is slightly different from what it was with PostScript. In particular, of the two translation coordinates in the NSFont matrix, only Y is actually effective. Developers should avoid using this method, and instead use fontWithName:size: where possible. In this release, there is also a recently-discovered bug that causes all fonts created via fontWithName:matrix: to have an incorrect size. (The size is erroneously multiplied by itself internally during initialization; this can be worked around by supplying a smaller size, and is intended to be fixed in subsequent releases.)

The method isBaseFont always returns YES for TrueType fonts.

A font's capHeight and xHeight are heuristically determined in the current implementation, since these values are not universally provided by the TrueType fonts.

Currently, the only font encoding supported is the NextStepEncoding. That is, only glyphs available in that encoding are reported by instances of NSFont, whether or not the font contains other glyphs. All font instances likewise report that their encoding is NextStepEncoding. This is a limitation that will be removed in the future.

The NSFont method glyphWithName: is not currently implemented in CoreGraphics, and will not return correct results.

The method boundingRectForGlyph: has a bug where it will crash.

Kerning tables are not currently supported by CoreGraphics; hence kerning information is not available via NSFont methods in this release. (I.e., all fonts appear to have no kerning.)

The only glyph packing actually supported in the system is NSNativeShortGlyphPacking. All fonts are presumed to have encoding vectors representable as an unsigned short int. The NSText system only uses NSNativeShortGlyphPacking. The conversion function NSConvertGlyphsToPackedGlyphs() may still be used to obtain other packings; but they are no longer useful with any text system components.

The older PostScript notions of font encoding variability and configurability are being phased out. Developers should avoid using the methods mostCompatibleStringEncoding and encodingScheme. Instead, when it is necessary to determine whether a given glyph is available,developers can use the method glyphIsEncoded:. In addition to providing better international support for complex script rendering, it is intended in the future to make the "Unicode CMAP" accessible via NSFont API, and to utilize each font's glyph IDs directly.

The method widthOfString: is deprecated and should not be used; it is provided for backward compatibility only. This method is only applicable in the case where all characters in a string are known to be renderable with the receiving font in a one-to-one correspondence between characters and glyphs. In all other cases, it is almost guaranteed to not reflect what will actually happen when a string is rendered through the text system. Furthermore, characters of the string which cannot be rendered, as determined when this method is called, are ignored in the width calculation.

Use of a font's bounding rectangle for determining default line height is being phased out in favor of more typographically correct notions using a font's ascent, descent, and "line gap". Developers should use the new method defaultLineHeightForFont when they need to know how tall they should set lines. In the current implementation of the text system, this may not be consistently applied.

The programs buildafmdir and cacheAFMData are obsolete and no longer shipped. These were formerly used for building the font cache formats used by older NextStep systems prior to OpenStep Version 4.0. They have not been used on recent systems, but were kept for compatibility in networks combining machines with old and new operating systems. Their product files, .fontdirectory and .fontlist, (in each font library directory) are likewise obsolete. These files are only used by machines running earlier operating systems than OpenStep Version 4.0.

The replacement program is fcache for caching data used by the font panel. On this release, fcache is only effective when executed by the administrator (root) and only stores information for fonts in the location described above.

The programs prebuild and screenafm are likewise obsolete. There are no replacements. (These programs were formerly used to process hand-tuned bitmaps in PostScript fonts.)

The size of the NSFont class instances have changed, which could generate some binary compatibility problems for subclassers. However, given that NSFont is rarely subclassed, this should not be a problem in general.

As mentioned above, the CoreGraphics framework does anti-aliased drawing. Because anti-aliased fonts tend to have less crisp edges and may cause problems with on-screen readability at small sizes, the AppKit's NSFont implementation by default will use anti-aliased fonts only at 16points and larger. In this release, that size may be controlled through the user default NSMaxScreenFontSize. To globally decrease the size at which anti-aliased fonts are used font above 12 points, for example, a user may execute the following command line:
defaults write NSGlobalDomain NSMaxScreenFontSize 12.0
That tells NSFont to use anti-aliased fonts above 12.0 points globally, and to use screen-fonts up to and including 12.0 points. As with any other default, this may be restricted to a particular application by substituting the application domain, and applications may set or register the value internally via NSUserDefaults.


FontPanel

The font panel formerly updated its text-preview area with the name and size of the currently selected font. This was sometimes problematic and unreliable. The font panel now displays the face name and size in a heading field above the Family/Face browser, leaving the text-preview field available strictly for sample text. The field may be re-sized to zero height if sample text is not desired.

As before, the font panel attempts to render the sample text in the currently selected font (if a single font is selected). If the font is unable to render the sample text because appropriate glyphs are unavailable, another font may be chosen automatically. The mechanism that formerly attempted to choose appropriate sample text is expected to be replaced in a future release.


BezierPath

The following glyph rendering functions in NSBezierPath are not functional in the Developer Preview release:
- (void)appendBezierPathWithGlyph:(NSGlyph)glyph inFont:(NSFont *)font;
- (void)appendBezierPathWithGlyphs:(NSGlyph *)glyphs count:(int)count inFont:(NSFont *)font;
- (void)appendBezierPathWithPackedGlyphs:(const char *)packedGlyphs;

CStringText

NSCStringText, which was obsoleted in MacOS X Server developer releases, has been removed from the system. You should be using NSTextView instead.

If you unarchive nib files which contain NSCStringText instances, you will get a warning and the instance will be converted into a NSTextView, preserving the attributes that are settable through Interface Builder's inspector. Note that there might still be problems using that nib file, if you send that instance methods only NSCStringText understands. You should replace the NSCStringText with a NSTextView in Interface Builder.


Sound

Sound playback in NSSound objects has been disabled for this release.


Preferences

User defaults (as saved by NSUserDefaults and CFPreferences) are now stored in the Library/Preferences directory in the user's home folder, in XML files. One side-effect of this change is that MacOS X Server preferences are distinct from MacOS X preferences. The first time you log in to MacOS X, the MacOS X preferences will be created automatically for you from your MacOS X Server preferences. (This might take up to a minute.)


Remote Launching

You cannot launch an AppKit application from a remote login session because it will fail to connect to the Pasteboard Server due to security constraints. Workaround: from the remote login session, you can first launch a remote instance of the Pasteboard Server in the background with:
  /System/Library/CoreServices/pbs -a &
Applications subsequently launched from this session will connect to this Pasteboard Server. Note however that it will not be possible to copy and paste or drag between applications launched this way and other applications launched locally on the target system.


Scripting

AppleScript support is not functional in this release.


Document

NSWindowController now has a public method called synchronizeWindowTitleWithDocumentName which is called whenever the NSDocument has changed in such a way that the window title needs updating. Subclasses can override this if they want to change the way the window title is constructed.

Opening a document of a type that your NSDocument subclass supports for reading but not writing will now result in an untitled document, since the document will not be able to be saved back the way it was loaded.

Reverting a clean document will still perform the revert, but will no longer confirm the revert with an alert panel.

There is a new initWithNibPath:owner: method on NSWIndowController that allows you to specify the full path to the nib file instead of just the name. This is useful when the nib is in a non-standard location (ie in the same bundle as the class that is loading it).

NSWindowController now has a setWindow: method that can be used to set (or unset) the window managed by the controller. Setting the window to nil will not cause the nib to be reloaded next time someone asks for the window.


Text

Fixed a NSLayoutManager bug that could cause display of lines from a different text container in multi-container text setups where lines overlap.

Fixed a NSLayoutManager bug which caused containers with holes to have various display glitches.

Paging up in a non-editable text view will no longer page down.

One new method has been added to the NSSimpleHorizontalTypesetter class for the convenience of subclassers:
- (void)willSetLineFragmentRect:(NSRect *)aRect
forGlyphRange:(NSRange)aRange
usedRect:(NSRect *)bRect
If implemented by subclasses, this is called within the method layoutGlyphsInHorizontalLineFragment:baseline: after laying out each line fragment, and immediately before calling setLineFragmentRect:forGlyphRange:usedRect: in the NSLayoutManager to record the used line fragment rectangles. This is intended for subclasses to be able to affect e.g., linespacing globally. The "used" rect is expected to be smaller than or equal to the "aRect".


PopUp, Menu

Fixed a menu bug affecting the precedence of key equivalents between service items and regular items when two items want the same key equivalent.

Fixed some problems with popup drawing where the title was either cut off too soon or it ended up overlapping the popup arrows.

Popups now draw the dotted line key view indicator when they are first responder on Windows.


Pasteboard

The serialization format used for putting property lists on the pasteboard now uses XML. Clients of NSPasteboard that used setStringForType: and setPropertyListForType: are unaffected by this change. Clients that assumed the data format was that used by NSSerializer and used setDataForType: should convert to the above methods wherever strings or property lists are the content of the pasteboard. The serialization format used by the pasteboard is subject to further change. To be insulated from future changes, use -setStringForType: and setPropertyListForType: wherever strings or property lists are the content of the pasteboard.

Copy and paste between all applications (Yellow Box, Carbon, and Blue Box) is expected to work using the existing NSPasteboard and Scrap and interfaces. It does not work in this release. Type conversion between traditional OpenStep and MacOS types is expected to be present in a future release.


Dragging

There is no user-visible feedback (cursor change) resulting from setting the drag operation in response to NSDragging protocol methods sent to the dragging destination. Dragging between Carbon and Yellow applications is also not working in this release.


Services

Services for most applications are not available in the services menu in this update, as make_services fails to look in the directories where applications live. Workaround is to execute make_services by hand; in a shell window, do:
make_services /System/Applications /System/Demos /System/Developer/Applications

MovieView

NSMovieView is not yet functional as QuickTime is not available in the Developer Preview release.


Window Manipulation

Due to changes in the graphics and window management subsystems, some bugs have been introduced in window manipulations:

Dragging an item from an application window will bring the application forward, perhaps obscuring the destination window. For example, dragging an icon from the desktop will bring most recently key Viewer window forward. Workaround is to move the key window of the owning app out of the way of your destination window before initiating a drag.

Windows may be ordered forward incorrectly. If you have two windows open in a given application and one of those windows is key, that same window will come forward the next time you activate the application, regardless of which window you click on to initiate the activation. Workaround is to click on the desired window to bring it forward after activation.



Notes specific to Mac OS X Server

The AppKit includes the following new features and changes between Developer Release 2 and MacOS X Server 1.0. Note that in some cases the notes below might be invalidated by changes in MacOS X Developer Preview 1 and 2, listed above.


Scripting

Mac OS X Server introduces support for scriptable Yellow applications. The support is still considered beta-quality, and is provided for developers to get started making their applications scriptable. See the scripting release note and the documentation for more details. TextEdit and both the Java and Objective-C version of Sketch support scripting and can be used as examples of how to implement scripting in a Yellow application.


ActiveX (Windows only)

Yellow frameworks now have support for ActiveX when running on Windows. See the ActiveX release note for more details. The WebBrowser example shows how to use ActiveX embedding.


Sound

A new class, NSSound, has been added to the AppKit. This class offers simple cross-platform sound-playing capabilities to applications. Editing and recording of sounds is not supported, nor is manipulation of sound parameters (volume, left/right gain, etc.). The sound formats that are understood are the a-law, u-law, 8- and 16-bit signed and unsigned linear encodings of the Microsoft WAV and NeXT/Sun SND (AU) formats. These formats are understood on either platform.

The NSButton and NSButtonCell classes have setSound: methods that can be used to associate a sound with a button.


MovieView

The AppKit now includes an NSMovieView that can be used to play QuickTime movies. It contains sufficient functionality to create an application such as MoviePlayer but does not give full access to all of the QuickTime APIs for content creation. The movie is always resized to fill the whole view and the view can be embedded in another view with appropriate clipping. Note that loading a movie view takes a few seconds when first starting to load the QuickTime libraries. There is an outstanding bug which causes the application to crash if the view is resized to zero width or height.


Binary compatibility on Windows

Due to a bug fix in the Objective-C runtime, binaries from DR2 and previously will not run on Yellow Box for Windows 1.0. These applications should be fully recompiled.


ColorSync support in NSBitmapImageRep

The property dictionary in NSBitmapImageRep has a key declared in NSBitmapImageRep.h as NSImageColorSyncProfileData. The value for this key is an ICC profile.

In 1.0, ColorSync correction of images during display is supported on all architectures. Prior to 1.0 it was only supported on ppc.

Also, when the bitmap image rep is turned into a TIFF representation, the ICC profile is written into the tiff representation. Prior to 1.0, profiles embedded in tiff representations were only supported during reading.

If an NSImage replaces an NSBitmapImageRep by an NSCachedImageRep, the color sync profile is consumed and no longer part of the property dictionary. The values of the pixels in the cached image rep are the ColorSync corrected ones.


Apple Menu items

You may want installation of your application to result in additional items appearing in each user's Apple Menu. To do this, you need to install a bundle in the library search path. For example, if your application was being installed in /Local/Applications, you would add a bundle to /Local/Library/AppleMenu.

The bundle must have the extension .appleMenuItems. Inside the bundle there should be a file AppleMenuItems.plist. If the bundle is localized, there would be a file, AppleMenuItems.strings, in each .lproj for which it is localized. Only the user-visible title of the item needs to be localized.

The format for the plist is not explicitly documented. There is however a substantial example inside the AppKit at /System/Library/Frameworks/AppKit.framework/Resources/English.lproj/AppleMenuItems.plist and /System/Library/Frameworks/AppKit.framework/Resources/English.lproj/AppleMenuItems.strings.

Currently all Apple Menu items found via these search paths are collected and localized once per login. The items become the backdrop against which users make their individual customizations. A user with no customizations sees all the items.


TextAttachmentCell Protocol

In order to give attachments more information about the environment they are being asked to draw in, the NSTextAttachmentCell protocol has been extended. The following methods have been added to the protocol:
- (void)drawWithFrame:(NSRect)cellFrame
inView:(NSView *)controlView
characterIndex:(unsigned)charIndex;
- (BOOL)trackMouse:(NSEvent *)theEvent
inRect:(NSRect)cellFrame
ofView:(NSView *)controlView
atCharacterIndex:(unsigned)charIndex
untilMouseUp:(BOOL)flag;
- (NSRect)cellFrameForTextContainer:(NSTextContainer *)textContainer
proposedLineFragment:(NSRect)lineFrag
glyphPosition:(NSPoint)position
characterIndex:(unsigned)charIndex;
Existing applications and object files are binary-compatible and do not require recompilation. However, under certain circumstances, you will need to make source changes to recompile existing conformers to the NSTextAttachmentCell protocol. Subclasses of the class NSTextAttachmentCell do not need to be changed; that class implements the new methods by calling the older -cellSize, -cellBaselineOffset, -drawWithFrame:inView:, and -trackMouse:inRect:ofView:untilMouseUp: methods. However, other classes which conform to this protocol will have to be modified in order to recompile. The simplest change is to simply remove the protocol from the class (i.e. remove "<NSTextAttachmentCell>" from the @interface line for your class); this will produce warnings when you recompile, but the resulting application or framework will work as expected. A more complete fix is to implement the new methods to call the old ones, exactly as the class NSTextAttachmentCell does. The most straightforward implementation appears below:
- (NSRect)cellFrameForTextContainer:(NSTextContainer *)textContainer
proposedLineFragment:(NSRect)lineFrag
glyphPosition:(NSPoint)position
characterIndex:(unsigned)charIndex {
NSRect result;
result.origin = [self cellBaselineOffset];
result.size = [self cellSize];
return result;
}
- (BOOL)trackMouse:(NSEvent *)theEvent
inRect:(NSRect)cellFrame
ofView:(NSView *)controlView
atCharacterIndex:(unsigned)charIndex
untilMouseUp:(BOOL)flag {
return [self trackMouse:theEvent inRect:cellFrame ofView:controlView untilMouseUp:flag];
}
- (void)drawWithFrame:(NSRect)cellFrame
inView:(NSView *)controlView
characterIndex:(unsigned)charIndex {
[self drawWithFrame:cellFrame inView:controlView];
}
When writing a new class that conforms to the NSTextAttachmentCell protocol, first decide whether you need the added information in the new, richer methods. If not, simply implement these methods to call the older, simpler methods, as shown above. If you want to take advantage of the richer methods, however, you should implement the richer methods, then override the older methods to call the richer ones, passing dummy arguments. For instance, if you want to use the text container and line fragment information when sizing your attachment, implement -cellFrameForTextContainer:proposedLineFragment:glyphPosition:characterIndex: to properly calculate the size and location of your cell. Then implement the older methods -cellSize and -cellBaselineOffset to call this method, passing dummy arguments (your -cellFrameForTextContainer:.... method should be tolerant of this case, and fall back to some simple sizing algorithm). This gives you:
- (NSRect)cellFrameForTextContainer:(NSTextContainer *)textContainer
proposedLineFragment:(NSRect)lineFrag
glyphPosition:(NSPoint)position
characterIndex:(unsigned)charIndex {
NSRect result;
if (!textContainer) {
// Do some simple size calculation here
...
} else {
// Do your full size calculation here
...
}
return result;
}
- (NSPoint)cellBaselineOffset {
return [self cellFrameForTextContainer:nil proposedLineFragment:NSZeroRect
glyphPosition:NSZeroPoint characterIndex:NSNotFound].origin;
}
- (NSSize)cellSize {
return [self cellFrameForTextContainer:nil proposedLineFragment:NSZeroRect
glyphPosition:NSZeroPoint characterIndex:NSNotFound].size;
}
The AppKit text system will never call the older methods; however, other classes that check for the protocol might, so you should make sure to implement the complete set.

In addition to the above changes, the following methods were added to NSLayoutManager to allow this to work:
- (void)setAttachmentSize:(NSSize)attachmentSize forGlyphRange:(NSRange)glyphRange;
- (NSSize)attachmentSizeForGlyphAtIndex:(unsigned)glyphIndex;
- (void)showAttachmentCell:(NSCell *)cell inRect:(NSRect)rect
characterIndex:(unsigned)attachmentIndex;
The last one deprecates the following method, which will continue to work in 1.0:
- (void)showAttachmentCell:(NSCell *)cell atPoint:(NSPoint)point;

Using NSURL to load resources

NSURL's API has been enriched to make it possible to load resources from the network and the web, either in the foreground or the background. To load an URL in the foreground, call resourceDataUsingCache:passing YES or NO, depending on whether you wish to use the cache. If you use the cache, NSURL will see if it or an equivalent URL has already been loaded and saved in the cache. If so, it will return the cached resource data. If not, it will start a fresh load of the URL, returning only after the URL's data has been fully loaded. If you do not use the cache, a fresh load will be started regardless. To load an URL in the background, call loadResourceDataNotifyingClient:usingCache:. This method will start the background load, then return immediately. As the resource is loaded, the client will receive messages from the NSURLClient informal protocol (if the client implements them):
@interface NSObject(NSURLClient)
- (void)URL:(NSURL *)sender resourceDataDidBecomeAvailable:(NSData *)newBytes;
- (void)URLResourceDidFinishLoading:(NSURL *)sender;
- (void)URLResourceDidCancelLoading:(NSURL *)sender;
- (void)URL:(NSURL *)sender resourceDidFailLoadingWithReason:(NSString *)reason;
@end
The client will receive some number (possibly zero) of URL:resourceDataDidBecomeAvailable: messages, followed by exactly one of URLResourceDidFinishLoading:, URLResourceDidCancelLoading:, or URL:resourceDidFailLoadingWithReason:. The client need only implement those methods that it is interested in receiving.

NSURLHandle and its subclasses:

An NSURL loads its resource by using a helper object of the class NSURLHandle. NSURLHandle itself is an abstract superclass, which defines the way by which URLs communicate with their handles. Subclasses of NSURLHandle register for a particular scheme (http, ftp, file, etc.), then implement the actual loading mechanism for that scheme. Currently, Foundation only provides subclasses for the file and http schemes.

Each NSURLHandle subclass also defines a number of properties for the scheme it services. For instance, the permissions, type and size of a file are all properties of file URLs (URLs of the form file:///some-path). You can ask an URL for one of its properties by sending it the propertyForKey: message, passing the key for the property you want. HTTP URLs provide their HTTP header data as properties; use the name of the header field you are interested in as the key. File URLs provide their file attributes as properties; use the file attribute strings defined in NSFileManager.h.

Although there are a number of convenience methods available on NSURL for loading resources and querying properties, some applications will find that the functionality exported by NSURL is not sufficient for its needs. For more extensive control, you should get the NSURLHandle from the NSURL, then message the handle directly. You can do that by sending the NSURL the URLHandleUsingCache: message. For further information about NSURLHandle, look at the header file, NSURLHandle.h.

Writing your own NSURLHandle subclass:

One thing a framework or application may want to do is add the ability to handle a new scheme. For instance, you may want to add ftp handling, or perhaps your own custom scheme. You can do this by subclassing NSURLHandle. Your subclass will need to override and implement the following methods:
+ (BOOL)canInitWithURL:(NSURL *)anURL;
+ (NSURLHandle *)cachedHandleForURL:(NSURL *)anURL
- initWithURL:(NSURL *)anURL cached:(BOOL)willCache;
- (id)propertyForKey:(NSString *)propertyKey;
- (id)propertyForKeyIfAvailable:(NSString *)propertyKey;
- (BOOL)writeProperty:(id)propertyValue forKey:(NSString *)propertyKey;
- (BOOL)writeData:(NSData *)data;
- (NSData *)loadInForeground;
- (void)beginLoadInBackground;
- (void)endLoadInBackground;
Your subclass should implement canInitWithURL: to return YES if it can service the given URL, and NO otherwise. cachedHandleForURL: should look in the cache (maintained by your subclass) for an existing handle that services an URL identical to the one passed. If so, the cached handle should be returned. If not, a new handle should be created for the URL, stored in the cache, then returned. initWithURL:cached: is the designated initializer for NSURLHandle; the second argument specifies whether the handle will be placed in the cache.

propertyForKey: should fetch the value for any properties that your subclass defines, and return nil for any unrecognized properties. propertyForKeyIfAvailable: should return nil unless the property is already readily available.

If your subclass allows writing out properties or data, you should implement writeProperty:forKey: and writeData: to attempt to write out their arguments, then return YES if the write succeeded, and NO otherwise. Otherwise, you should implement them to simply return NO.

The last three methods, loadInForeground, beginLoadInBackground, and endLoadInBackground do the meaty work of your subclass. They are called from resourceData, loadInBackground, and cancelLoadInBackground respectively, after checking the status of the handle. (For instance, resourceData will not call loadInForeground if the handle has already been loaded; it will simply return the existing data.) loadInForeground should synchronously fetch and return the URL's resource data. beginLoadInBackground should start a background load of the data, then return. As the background load progresses, your subclass should message itself with didLoadBytes:loadComplete:, passing the bytes received, and whether the load has finished. If the load fails at any point, your subclass should call backgroundLoadDidFailWithReason:, passing a human-readable string giving the reason for the failure. NSURLHandle implements these methods to inform its clients (including the URL itself) of the new status. Finally, your subclass should override cancelLoadInBackground to stop a background load in progress. Once a handle has received a cancelLoadInBackground message, it must not send any further didLoadBytes:loadComplete: or backgroundLoadDidFailWithReason: messages.

Now all that remains is to inform NSURLHandle of your new subclass; you do this by sending the NSURLHandle class the registerURLHandleClass: message, passing your subclass as the argument. Once this message has been sent, as NSURLHandle is asked to create handles for a given URL, it will in turn ask your subclass if it wants to handle the URL. If your subclass responds YES, NSURLHandle will instantiate your subclass for the URL.


Using NSUndoManager from Java

Because the invocation-based undo registration mechanism is unavailable in Java, the Java API of NSUndoManager has been enriched. The following method has been added to NSUndoManager:
public native void registerUndoWithTargetAndArguments(
java.lang.Object target,
com.apple.cocoa.foundation.NSSelector selector,
java.lang.Object arguments[]);
This allows the caller to put an arbitrary method invocation on the undo stack. The first argument is the intended receiver for the method, the second argument specifies the method, and the third argument is the array of arguments to be passed.

Note that the arguments array is an array of Objects. When your method takes scalar types, you should use the equivalent Java wrapper classes in the arguments array. For instance a method which takes an int should build a java.lang.Integer instance that contains that int to put into the arguments array. The undo manager will resolve all this by the time it needs to build the invocation to send. See the Java version of the Sketch application's source code for an example of the use of this new method.

There is a known bug which prevents float arguments (registered as java.lang.Float objects) from being properly registered; Methods which take floats will not be able to be undone properly at this time. The argument will always be zero by the time your method is invoked from the undo manager. Sketch has this problem with the setStrokeLineWidth() method in the Graphics class. You can work around this by having your method take a java.lang.Float instead. This bug should be addressed in an upcoming release.


Using Undo with the Text System

A design flaw has been discovered when using undo with the AppKit text system. If you have a text view and have enabled undo with it by calling [myTextView setAllowsUndo:YES], the undo stack managed by the text view will become corrupted if the text storage is manipulated directly. A handful of methods on NSTextView (the methods inherited from NSText of the form -replaceCharactersInRange:....) will also corrupt the undo stack. Once corrupted, calls to undo and redo will have unexpected results, possibly crashing the application. To avoid this, we recommend that you either manipulate the text only through the safe NSTextView methods, manage the undo stack yourself, or disable undo. This bug will be resolved in a forthcoming release.


TableView

Column identifiers used with NSTableView's "autosaveTableColumns" feature must conform to the NSCoding protocol. NSTableView will raise an exception if the user attempts to perform the autosave (into User Defaults) on a table column identifier that is not an archivable object. In DR2, the view would allow one to attempt this, and the program would crash mysteriously during User Defaults writing.

The autosave feature is only actually enabled when there is an autosave name set. code should call setAutosaveName: before calling setAutosaveTableColumns:YES. In previous releases, this would autosave any nameless tableview with the same key, "NSTableView Columns *nil*".

The correct way to use this feature for NSTableView instances in NIB files is to set the name and enable it after the NIB file is loaded and before display occurs. The "awakeFromNib" method in a controller class is a good place to do this.

Because of this autosave feature, notifications of column width changing are suspended while a NSTableView is tiling itself or otherwise laying itself out by a user column-resize operation. The columns are saved upon completion of the layout operation. Were the notifications not suspended, the setWidth:calls during layout would cause notifications to be sent and column settings to be saved. This change prevents autosave from happening during layout and resizing operations.

Note: Developers may find that programs which utilized the autosave feature in DR2 can crash or raise an exception when trying to read old defaults under the new regime. (The exception would typically occur in methods called through the private method _readPersistentTableColumns; and the NSLog message will state that NSInlineUnicodeString does not respond to the bytes method.) The crash can be remedied by first removing the old autosave defaults for that application. (Use "defaults delete TheApp TheKey", or when in doubt, "defaults delete TheApp" to remove all of the defaults for the offending application.

Columns are saved by column identifier. In the DR2 release, the column identifier was expected to always be an NSString, though it is properly an "id" type. In this release, the column identifier can be any object that responds to the NSCoding protocol (though typically an NSNumber of an NSString).

Some notes on cell editing and data reloading: When the reloadData method is called, any cell that is in the midst of being edited will lose the editing changes currently in progress. (I.e., a cell that has the blinking cursor at the time of the reload will lose whatever has changed.) This can be remedied by explicitly ending the editing session before the reload, which will preserve the data in the cell. Before sending reloadData to the Table View, send endEditingFor: to the window in which it lives. For example:
    [[myTabView window] endEditingFor:self];
[myTabView reloadData];

OutlineView

The delegate method outlineView:willDisplayOutlineCell:forTableColumn:item: was never being sent. This has been fixed so that it is called (if the delegate responds to it) just before the cell is drawn.

The method removeTableColumn: should not be used for the "outline table column", and if an attempt is made to do that (which would result in an inconsistent state), the method will log an error and no change will take place. Use the setOutlineTableColumn: method to properly replace the outline table column if necessary. First, add a new column if you need to, then use setOutlineTableColumn: to switch to the new table column, then remove the old column if desired.


Notes on Support for the "Euro" Currency Sign

Most of the fonts shipped with this release have not been modified to include the new "Euro" currency sign of the European Monetary Union. The Charcoal font, however, has been modified to include this glyph in the encoding position formerly reserved for the International Currency Sign, a seldom-used character. It is expected that in the future if other fonts are modified, they would likewise include the Euro sign at this position. The character encoding for the Euro sign in the Unicode standard is U+20AC, as documented in Unicode Technical Report #8. (The International Currency Sign is encoded at U+00A4.)

To facilitate use of the Euro sign without system modifications, if new fonts containing it are added by users or other vendors, both the character for the Euro sign and for the International Currency Sign are rendered with the glyph encoded at 0x00A8 in the "NextStep" font encoding.

In other words: in the Charcoal font, the glyph for the International Currency Sign is unavailable, having been replaced by the glyph for the Euro sign. In the other fonts, the glyph for the Euro sign is unavailable. However, all NextStep-encoded fonts respond as if the glyph for the Euro sign were encoded at 0x00A8.

To display the proper glyph for the Euro sign in plain text, you may use the Charcoal font. To display the proper glyph in RTF or other fancier formatted documents, you may enter the character U+20AC, select it, and change the font of that one character to Charcoal.


Notes on Keyboard Support for the "Euro" Currency Sign

Most of the keyboard layouts shipped with Mac OS X Server now have the Euro sign attached to the Alt-Shift-4 key combination. If the keyboard layout you have chosen is not configured this way, or if you wish to change the key combination for generating the Euro, you can use Keyboard.app which can be found in /System/Demos.

Because keymaps currently do not support the assignment of actual Unicode characters, thetechnique for assigning the Euro sign to a key is not obvious. To assign the Euro to a key, you should use the 0xa0 encoding slot of the Symbol character set. This encoding slot is unused in the standard Symbol encoding.

To assign this to a key, open your keyboard mapping file in Keyboard.app, select the key you want on the picture of a keyboard and make sure that the checkboxes for any modifiers you want are checked. For example, to assign it to Alt-Shift-4, select the four key and check the Shift and Alternate checkboxes. Then, using the Character Code Palette (available from the Tools menu), select the Symbol encoding from the popup at the bottom of the window and drag the chip for 0xa0 onto the keyboard and drop it on the key that you want to assign. Slot 0xa0 is the 1st column of the 11th row of the Character Code Palette. When you have assigned the Euro sign to the key you want, save the keyboard mapping into your ~/Library/Keyboards directory (creating the Keyboards directory if necessary), and use Preferences.app to select your new keyboard mapping.


Typesetter

NSTypesetter has been made a public class in this release. The class NSTypesetter itself is abstract. The one concrete subclass is NSSimpleHorizontalTypesetter, which is the class used as the default throughout the system. Some instance variables of the concrete class are accessible for use by subclassers.

The following NSLayoutManager methods have been exposed to support use of custom NSTypesetter subclasses:
- (NSTypesetter *)typesetter;
- (void)setTypesetter:(NSTypesetter *)typesetter;
- (unsigned)getGlyphsInRange:(NSRange)glyphsRange
glyphs:(NSGlyph *)glyphBuffer
characterIndexes:(unsigned *)charIndexBuffer
glyphInscriptions:(NSGlyphInscription *)inscribeBuffer
elasticBits:(BOOL *)elasticBuffer

Browser

Some delegate methods of the NSBrowser (notably browser:columnOfTitle:) depend on the option-settings and state of the browser instance at the time the setDelegate: method is called, but the documentation is not clear on this point. It is best to take care of all option settings of the browser instance (such as setTitled: and setTakesTitlesFromPreviousColumn:) before setting the delegate via setDelegate:.


Window

NSWindow now has -isZoomed API to let you ask whether a window is currently zoomed. The answer will be YES if hitting the zoom box or calling the zoom: method would cause the window to restore the last user state. It will be NO if hitting the zoom box would cause the window to zoom.


DocumentController

The Java signatures for the following methods have changed to be more specific. This change will require a recompile of Java applications that use the document architecture.
public static native NSDocumentController sharedDocumentController();
public native NSDocument makeUntitledDocumentOfType(java.lang.String);
public native NSDocument makeDocumentWithContentsOfFile(java.lang.String, java.lang.String);
public native NSDocument makeDocumentWithContentsOfURL(java.net.URL, java.lang.String);
public native NSDocument openUntitledDocumentOfType(java.lang.String, boolean);
public native NSDocument openDocumentWithContentsOfFile(java.lang.String, boolean);
public native NSDocument openDocumentWithContentsOfURL(java.net.URL, boolean);
public native NSDocument currentDocument();
public native NSDocument documentForWindow(com.apple.cocoa.application.NSWindow);
public native NSDocument documentForFileName(java.lang.String);
These methods all used to return java.lang.Object in DR2.


WindowController

The Java signatures for the following NSWindowController method has changed to be more specific. This change will require a recompile of Java applications that use the document architecture.
public native NSDocument document();
This method used to return java.lang.Object in DR2.


Application

activateIgnoringOtherApps: will now unhide and activate a hidden application if flag is YES. In DR2 and previous releases, this method had no effect on a hidden application.

NXOpen, NXOpenTemp, and NXPrint are no longer recognized as command line options. Any use of these keywords should be replaced by NSOpen, NSOpenTemp, and NSPrint, respectively.


Threading

It is now possible to create a window on a secondary thread.

It is now possible to call [NSApplication postEvent:atStart:] from a secondary thread. This will result in delivery of the event to the event queue on the main thread.

In DR2, multi-threaded applications could hit a race condition where a font defined on one thread was not accessible on another. This has been fixed for drawing fonts. The fix does not apply to printing fonts, but this should not be a problem as it is not expected that an application will be printing from two threads at once.

For additional release notes on threading support please see ThreadSupport.html.


Using NSFileHandle with sockets on Windows

Because read() and write() do not work on sockets on Windows, a file handle created with [[NSFileHandle alloc] initWithNativeHandle:(HANDLE)someSocketHandle] was not usable.

If read() and write() fail, the file handle implementation now tries recv() and send(), respectively, and a file handle created this way is now usable.

You may find it particularly convenient to go through the NSFileHandle API in cases where you do not know whether a handle is a socket or a handle to a regular file system file. For example, a child process whose parent set it up to read or write from a socket using stdin and stdout can successfully read from stdin and stdout using the file handle API, whereas stdio library calls such as getchar() and putchar() will fail.


Dragging on Windows

Due to an incorrect match between messages sent by the OLE drag manager and the NSDraggingDestination informal protocol, draggingEntered: was sent repeatedly and draggingUpdated: was not sent. Developers who have worked around these longstanding problems should remove their workarounds as of this release.


Continuous Completion in NSComboBox and NSComboBoxCell

A new method setCompletes: has been introduced. If completes is YES, after each change to the text of a combo box cell, completedString: is called. If the string returned by completedString: is longer than the existing text, the text is replaced, and the additional material is selected. If the user is deleting text or the selection (or insertion point) is not at the end of the text, completion is not attempted.

An implementation of completedString: is provided. If the combo box (or combo box cell) uses a data source, and the data source responds to comboBox:completedString: (or comboBoxCell:completedString: in the combo box cell case) the return value of this method is used. Otherwise, this implementation just goes linearly through the items until it finds an item which is suitable as the completed string. Subclassers of completedString: do not need to call super. It is ok to return nil (in which case no completion occurs). completedString: is generally not called directly.


ButtonCell

The constants NSMomentaryPushButton and NSMomentaryLight where reversed. If you called [NSButtonCell setButtonType:] with these constants, they would do the wrong thing. For compatability, these constant names have been kept but new ones with the correct naming have been introduced: NSMomentaryLightButton and NSMomentaryPushInButton.


StatusItem

The limit on the width of status bar items has been increased (to 10,000, basically unlimited).


MenuItem

The Windows implementation of NSMenuItem now supports black and white images for use as marks to indicate on, off, or mixed states. If custom images are not set, then the checkmark is used for the on state, the dash is used for the mixed state, and no image is used for the off state. The image will be centered in the bounds of the menu item icon.


ToolTips

In DR2 and previously, tool tips did not work in modal windows. They now do.


Standard About Panel

The following two methods have been added to NSApplication to allow putting up a standard About panel. The first one allows you to specify the various fields. Default values (as described below) are used for fields that are not specified. The second method, intended for target/action usage, simply uses all default values:
- (void)orderFrontStandardAboutPanelWithOptions:(NSDictionary *)optionsDictionary;
- (void)orderFrontStandardAboutPanel:(id)sender;
The following are keys that can occur in optionsDictionary:

"Credits": NSAttributedString displayed in the info area of the panel. If not specified, contents obtained from "Credits.rtf" in [NSBundle mainBundle]; if not available, blank.

"ApplicationName": NSString displayed in place of the default app name. If not specified, uses the value of NSHumanReadableShortName in the localized version of Info.plist. If that's not available, uses [[NSProcessInfo processInfo] processName].

"ApplicationIcon": NSImage displayed in place of NSApplicationIcon. If not specified, use [NSImage imageNamed:@"NSApplicationIcon"]; if not available, generic icon.

"Version": NSString containing the build version number of the application ("58.4"); displayed as "(v58.4)". If not specified, obtain from the NSBuildVersion key in infoDictionary; if not specified, leave blank (the "(v)" is not displayed).

"Copyright": NSString containing the copyright string. If not specified, obtain from the value of NSHumanReadableCopyright in the localized version InfoDictionary; if not available, leave blank.

"ApplicationVersion": NSString displayed as the application version ("MacOS X Server", "WebObjects 3.5", "ClarisWorks 5", ...). If not specified, obtain from the NSAppVersion key in Info.plist. If not available, leave blank; then the build version, if provided, is displayed as "Version 58.4".


Attributed Strings in FoundationJava

Note that although the NSAttributedString constructors from AppKit are listed in FoundationJava in the Yellow/Java APIs, these are still implemented in the AppKit and require AppKit to be linked in to be usable.


Text

The text object now supports more sophisticated underlining; you can underline by words, and by strikethrough. You can "or" together NSUnderlineByWordMask and NSUnderlineStrikethroughMask with the base underline style (NSNoUnderlineStyle or NSSingleUnderlineStyle) to get the desired effect.

In DR2 and previously, hyphenation could (especially with high hyphenation factors, above 0.8) cause display glitches (overwritten lines, for instance) in some rare circumstances. This is now fixed.

A leak in the text system that caused the text view and related objects to leak when undo was enabled has been fixed.


SplitView

The following delegate method:
- (void)splitView:(NSSplitView *)sender
constrainMinCoordinate:(float *)min
maxCoordinate:(float *)max
ofSubviewAt:(int)offset;
was deprecated in favor of:
- (float)splitView:(NSSplitView *)sender
constrainMinCoordinate:(float)proposedCoord
ofSubviewAt:(int)offset;
- (float)splitView:(NSSplitView *)sender
constrainMaxCoordinate:(float)proposedCoord
ofSubviewAt:(int)offset;
In 1.0, the old one will be called if it's still implemented.


View

New method lockFocusIfCanDraw has been introduced. Any thread drawing directly (eg. outside of the standard display mechanism) should use this method to check drawing validity before it starts drawing.


FileWrapper

The string encoding for a serialized directory wrapper is changed from NSNEXTSTEPStringEncoding to NSUTF8StringEncoding. This means non-ASCII characters in serialized RTFD data lose backward compatibility.


Java

The alpha versions of the Java APIs to the Yellow Box have been removed. They were provided in DR2 for compatibility only.



Notes Specific to Developer Release 2

The Application Kit includes these new classes, features, and changes since the first Developer Release. Many of the new features have been documented, so please refer to the documentation for more detail.


Java

The Java APIs to the Yellow Box, which were distributed in their alpha form in the first Developer Release, have undergone some changes and are now considerably more robust and finalized. Please see the Java APIs release note for details.


Document-Based Application Architecture

The new NSDocument, NSDocumentController, and NSWindowController classes ease the task of creating document-based applications. These classes encompass a lot of the behavior that applications commonly implement to deal with documents. Document-based applications that use these classes will be better suited to take automatic advantage of new features added to the Yellow Box.

Instances of NSDocument represent documents. NSDocument is abstract; you subclass it to add storage for the document and behaviors such as reading and writing. An NSDocument appears in the responder chain right after its window's delegate, and the NSDocument is set up to be the first-responder target for various actions such as save, revert, and print. In addition, NSDocument manages its window's edited status and implements much of the behavior required for undo and redo operations.

Each application has one instance of NSDocumentController, which manages the list of documents and implements application-wide behavior.

NSWindowController provides basic nib-file and window management. For simple situations (one document, one window), you will usually have one instance of NSWindowController per document. An NSWindowController can also be used to manage windows in non-document-based applications. Subclassing is optional.

A new project type, "Document Based Application," facilitates the initial setup required to create an application based on these new classes.


Data Types

To better support the new document object and the Finder (in upcoming releases), some changes were made in the contents of the Info.plist and CustomInfo.plist files found in application wrappers and bundles. See the release note on the Information Property List Format for details.


Undo Support

Enterprise Object Framework's EOUndoManager has been modified and made a new Foundation class, NSUndoManager. This class makes it easier for applications to support undo and redo operations. Clients register callbacks that the undo manager invokes when users request an undo or redo operation. NSUndoManager supports grouping and multiple levels of undo.

NSResponder now provides a method called undoManager; clients should use this method to get access to an NSUndoManager. The default behavior in NSResponder is to call the next responder; this usually ends up in NSWindow, which is in the responder chain. The default behavior of NSWindow is a bit more complicated; if the window has a window controller with a document, NSWindow implements this method by first looking to see if its document has an undo manager and returning it if that is so. Otherwise, NSWindow invokes the new delegate method undoManagerForWindow:If the delegate doesn't implement this method NSWindow creates and returns its own NSUndoManager.

The text system now also supports undo and redo operations.


Scripting

Although DR2 contains no scripting features, a release note has been provided to provide information to help you design your application so that it will be scriptable when the Yellow Box does provide scriptability. This release note also discusses the document architecture and undo features in some detail.


ActiveX (Windows Only)

The ActiveX framework (ActiveX.framework) brings together the first pieces of Yellow Box/ActiveX integration by allowing you to use ActiveX Automation objects in Objective-C. Note that this functionality is currently pre-alpha, meaning the packaging and APIs themselves are subject to change in the next release.

NSDispatchProxy is a concrete subclass of NSProxy that defines proxies for ActiveX Automation objects. When an NSDispatchProxy receives a message, in most cases it forwards the message through DCOM (Distributed Component Object Model) to the real ActiveX Automation object, supplying the return value to the sender of the message if one is forthcoming, and propagating any exception back to the invoker of the method that raised it. See the documentation provided in the framework for more information.


Multithread Features

The Application Kit and Foundation now provide more multithread safety, enough to support AWT's multithreaded drawing demands and allow developers to do a variety of tasks using multiple threads. Drawing from multiple threads is supported as long as each thread uses its own connection to the window server; this is easily accomplished by using the NSApplication factory method detachDrawingThread:toTarget:withObject:.


Status Bar

NSStatusBar and NSStatusBarItem are two new classes that provide a way to add items to a system-wide status area. These status-bar classes replace the use of application tiles as well as providing extended functionality. An application can add status-bar items that are strings, images, tool tips, or menus and can invoke an action in a specified target when users click on a status-bar item.

The same API is available on both Macintosh and Windows. On the Macintosh, the items appear on the right hand side of the menu bar. Under Windows, the status items appear as part of the taskbar notification area (usually right side of taskbar). The custom view feature is not supported under Windows.


Menu and Popup

The Apple menu is now automatically filled with a default list of applications and two special entries that represent the lists of recently used applications and documents. In this release there is no editor with which users can configure the contents of the Apple menu, and both the contents of the list and the storage for the contents is subject to change in the future.

The Application Kit "hack" of changing the first top-level menu to an Apple menu if its title is "Info" still works in this release; however, you should switch your menus to use a real Apple menu.

Any menu that is a part of an application's main menu can be torn off. To tear off a menu start tracking in it as if you were going to choose an item and drag off the bottom of the menu a little distance. The mouse button must be down to tear off a menu. The menus you tear off in an application are remembered and restored as you quit and relaunch the application.

Menus now support keyboard UI: While a menu is tracking you can now use the arrow keys to navigate. Since there is currently no way to start tracking the main menu through the keyboard, this isn't yet very useful for normal menus, but it means that you can use the keyboard to choose items in a popup or pulldown menu. When the focus is on an NSPopUpButton, pressing the space bar pops the menu up. Then you can use the arrow keys to move between items; press the space bar again to choose an item.

Control-click now show the context menu for a view if the view has one. The Control-click is not seen (as a mouseDown:) by views that have context menus. Views that do not have context menus still receive mouseDown:for Control-clicks. However, using Control as a mouse modifier is discouraged, even if you don't have context menus. Over time, Yellow Box applications provided by Apple will migrate away from using Control-click for anything but context menus.

User key-equivalent overrides: This feature is implemented but the UI for setting them is not in this release.

You can now specify the arrow position for bezel style and borderless pop-up menus.


ScrollView

You can now independently set the horizontal and vertical line and page scroll amounts.


SplitView

NSSplitView has additional delegate methods to allow you to constrain the resizing and collapsing of the view.


TabView

The new convenience method selectTabViewItemWithIdentifier:allows you to select a tab item by its identifier. As with the other methods in NSTabView, this method raises an exception if the identifier is invalid.


Workspace

In Developer Release 1 on MacOS platforms, application delegates did not receive applicationShouldTerminate:on power-off or logout events in addition to normal application termination. This now works properly. If the application delegate implements this method and returns NO, then the logout or power-off is cancelled.

Applications that need to distinguish between a termination associated with the end of a login session and a termination through a Quit (or Exit) command could do this by registering for the NSWorkspaceWillPowerOffNotification. This notification is posted prior to calling applicationShouldTerminate:.

Additional relevant events that occur later in the termination sequence are the posting of an NSApplicationWillTerminateNotificationand a corresponding message to the application delegate of applicationWillTerminate:, if it implements the method.

For documents managed by an NSDocumentController, it is not necessary for the application delegate to become involved in the save or cancel process.


Button

Buttons include a new feature makes the border of the button visible only when the button is enabled and the mouse is over the button. You can enable or disable this feature by invoking the method setShowsBorderOnlyWhileMouseInside:; the current setting of this attribute is returned by the method showsBorderOnlyWhileMouseInside. These two method are available in both NSButton and NSButtonCell and this setting is archived and restored. When you are dealing with matrices, invoke the cell methods directly.

You can override the mouseEntered:and mouseExited:methods added to NSButtonCell in order to make additional appearance changes. These methods are invoked when the button cell is enabled, the showsBorderOnlyWhileMouseInsideflag is set to YES, and the mouse enters or exits the button.


BitmapImageRep

The new method colorizeByMappingGray:toColor:blackMapping:whiteMapping:supports colorization of images. This method primarily maps grayscale user interface component images to different color schemes.

In this release NSBitmapImageRep has some preliminary support for ColorSync profiles in TIFF files. The profile is loaded and used if possible. It is not retained on save. Also, it works only on the PowerPC architecture.

As mentioned in the Developer Release 1 notes, NSBitmapImageRep now supports JPEG, GIF, and PNG reading and writing. This support is not finalized and will probably change for the first Customer Release to include additional formats using QuickTime codecs.

Because different image formats contain additional information, this information is stored as NSBitmapImageRep properties. You can set these properties in the image by using the setProperty:withValue:method and get the properties with valueForProperty:,or you can add or override the properties when creating the representation using representationOfImageRepsInArray:usingType:properties:and representationUsingType:properties:methods. The properties are stored in an NSDictionary using an NSString for the key. The following key/value pairs are currently defined:

- NSImageCompressionMethod:-- The TIFF compression method for TIFF files. The enumerated value is stored in an NSNumber.
- NSImageCompressionFactor:-- The TIFF and JPEG compression factor. The float value is stored in an NSNumber.
- NSImageDitherTransparency:-- Used for GIF output only. It is a boolean value stored in an NSNumber. If true, transparency is dithered to get an alpha channel effect.
- NSImageRGBColorTable:-- For GIF input and output. It consists of a 768 byte NSData object that contains a packed RGB table with each component being 8 bits.
- NSImageInterlaced:-- For PNG output; this value indicates that the output image is to be interlaced. It is a boolean value stored in an NSNumber.]


Color

Several new factory methods support additional system colors:

- keyboardFocusIndicatorColor:-- Color to use to draw the keyboard focus ring around text fields and buttons.
- headerColor:-- Background color for header cells in Table/OutlineView.
- headerTextColor: -- Text color for header cells in Table/OutlineView

MacOS X Server now supports dynamic updating of color schemes; if the user changes any of the system colors in the Preferences application, applications will be updated dynamically. If you create or cache any custom colors based on system colors, you might need to listen to the NSSystemColorsDidChangeNotificationand take appropriate action when the color scheme is updated.

As discussed above, NSBitmapImageRep also provides a method to colorize images; this method might come in handy when you are adopting bitmap images in the user interface to new color schemes.


New C Types

The typedefs NSPointArray, NSSizeArray, NSRectArray,and NSRangeArrayare added to Foundation and the AppKit to indicate methods and functions that take C-arrays of NSPoint, NSSize, NSRect, and NSRange.

Similarly, the typedefs NSPointPointer, NSSizePointer, NSRectPointer,and NSRangePointerare added to indicate methods and functions that return NSPoints, NSSizes, NSRects, and NSRanges by reference.

These typedefs do not really change the API, but they do clarify the intentions of the few methods taking pointers to structs, making it possible for the Java bridge to convert them correctly.


FontManager

The methods availableFontFamilies, availableMembersOfFontFamily:, and localizedNameForFamily:face:are added to provide more information about font families.


Window

NSScreenSaverWindowLevelhas been added to allow developers to place windows above everything else, including menus. NSDockWindowLevelhas been deprecated and should not be used.

The Application Kit now supports a utility look for panels. This is typically used for small nonmodal panels that float and hide when the application is deactivated, such as a tools palette. A utility window is a floating panel by default, but you can disable this behavior by invoking setFloatingPanel:with an argument of NO.

You can create utility windows programmatically with the NSUtilityWindowMaskstyle (which should be specified in conjunction with NSTitledWindowMask), or in Interface Builder, by enabling the "utility window" option in the Panel Attribute inspector.

The "Minimize" attribute, which was changed to windowshade windows in Developer Release 1, now either minimizes or windowshades depending on the user preference.

A known problem in this release is the behavior of windows marked as "Visible at launch" in Interface Builder. When an application is launched they become visible but they do not become key even though the application is active. For a window to become key, makeKeyAndOrderFront:must be explicitly invoked.


URL

An NSURL class has been added to the Foundation framework. In this release the class only supports file URLs.

Various classes in the Foundation and Application frameworks have new APIs that take URLs in addition to file names. For instance, NSData's initWithContentsOfFile:now has a parallel initWithContentsOfURL:. You can now get back an array of URLs from the open panel in place of the array of file names. If your application starts using these new APIs, it will inherit richer behavior (such as accessing files and resources over the network) when NSURL class is expanded in future releases.


HTML

NSAttributedString's initWithHTML:documentAttributes:method has been deprecated in favor of initWithHTML:baseURL:documentAttributes:, which provides a way to supply the appropriate base URL.

Please note that the prefix HTML is reserved and in use by the (currently private) HTML framework.This framework is dynamically loaded when the Application framework needs to parse HTML files; any conflicts in global names could lead to problems at that time.


Image

Invoking NSImage's imageNamed:method with images that don't exist can be costly, forcing a search of the application's main bundle and the Application framework. If you wish to detect such calls to this method, run your application with the NSLogMissingNamedImagesdefault set to YES (as with all defaults, this can also be specified through the command line).


Slider

The method setKnobThickness:currently has no effect.


Distributed Notifications

The Foundation framework now contains NSDistributedNotificationCenter, a class for sending notifications between processes on a single machine. In addition to the basic features in NSNotificationCenter, this class provides a way to set a suspension behavior on notifications: You can cause them to be delivered immediately to all applications, or delayed until the applications are not suspended. The Application Kit ensures that applications become suspended when they are deactivated.

Distributed notifications can be expensive if they are sent often and cause the receiving applications to wake up on delivery. For that reason you should use them sparingly and with the suspension behavior generally set to NSNotificationSuspensionBehaviorCoalesce.


BezierPath

There are significant changes in the NSBezierPath APIs, which are not yet documented. Please refer to the header file for the new API.

Compatibility was not maintained between the old and new APIs, so earlier code that used NSBezierPath should be recompiled.


Input Manager

This release introduces some additional input method API. At the core of interaction, insertText:and setMarkedText:selectedRange:can receive an instance of NSAttributedString as their arguments where they were restricted to NSString in the previous releases. Input servers are expected to query valid attributes with the validAttributesForMarkedTextmethod. Currently the following attributes are supported by NSTextView for marked text: Foreground color (NSForegroundColorAttributeName), background color (NSBackgroundColorAttributeName), and underline (NSUnderlineAttributeName).

This release provides more sophisticated programmatic interaction between the user and the input methods, including allowing an input method to track mouse events on text.

When Developer Release 2 ships, Apple's Developer Support web site will make available source code for a sample input method that uses the new APIs to implement a hex input method (allowing you to type a hex number to specify any Unicode character).


OutlineView and TableView

By invoking setAutosaveTableColumns:you can get the column configuration (such as ordering and sizes) of a table or outline view to be saved, per user, under a key specified via setAutosaveName:. This works much like the frame saving feature in NSWindow. Outline view also provides an additional method, setAutosaveExpandedItems:, to let applications save the expansion state of the viewed data. To enable this, you will also have to respond to the new data-source methods that allow the outline view to archive the items.

Additional delegate methods and notifications in NSOutlineView allow instances to communicate expansion and collapsing of items.


View

The printing method knowsPagesFirst:last:has been deprecated in favor of knowsPageRange:, which is easier to map to Java. The old method will keep on working but will no longer be documented.


Text

Invoke setAllowsUndo:with an argument of YES to enable undo in the text system.


IB Connectors

If you write your own connection inspector for IB, you may wish to use the NSNibControlConnector, NSNibOutletConnector, and the NSNibConnector classes. NSNibControlConnector provides a target/action connection between objects in a nib file. NSNibOutletConnector provides an outlet connection between objects in a nib file. NSNibConnector is the common base class; you may wish to subclass it for your own custom connectors between objects.


DataLinks

DataLinks, which were made obsolete between NextStep and OPENSTEP releases, have been removed from the framework.


ComboBox

NSComboBoxCell now provides automatic completion of typing.


Keyboard UI

The way keyboard UI is started on MacOS X Server has been modified. In windows without editable textfields, hitting Tab will enter you into keyboard UI mode; until that time, keyboard focus will not be on any UI object. In windows with editable textfields, if an initial first responder has not been specified, the textfield will have the focus when the window is brought up. On Windows the situation is as it was; that is, it works like Windows does.

On MacOS X Server, Command-up-arrow and Command-down-arrow used to change the ordering of windows (without making them key). This is no longer the case.

The Escape key (Esc) now no longer does escape completion by default; instead, it cancels the current action (usually dismissing panels). To change Escape back to completion, create or edit the DefaultKeyBinding.dict file in ~/Library/KeyBindings so that it contains this line:
{
"\033" = "complete";
}

CStringText

Consider NSCStringText and all related API (everything in obsoleteNSCStringText.h) to be deprecated. Although this code will keep working for awhile, it is highly recommended that you switch over to the new text system, which provides much more functionality in a much cleaner way. If there are any reasons that prevent you from moving to the new text system, please let us know through Developer Support.



Notes Specific to Developer Release 1

In DR1, the Application Kit includes these new classes, features, and changes since OpenStep 4.2:


NSPICTImageRep

A class for objects that represent PICT images. For the Developer Release, only bitmap PICTs work.


NSProgressIndicator

A class for objects that implement a determinate or indeterminate progress indicator. The indeterminate progress indicator can be animated in a separate thread, allowing its use even in computation code that doesn't use the run loop.


NSTabView and NSTabViewItem

Classes for displaying multiple views using tabs.

NSOutlineView

A subclass of NSTableView that implements an outline representation of hierarchical data. Like NSTableView and NSBrowser objects, NSOutlineView objects use a data source (separate from the delegate) to display the data lazily.


NSColor

New factory methods create objects that represent additional user interface colors.


NSColorPanel

As does the Font panel, the Color panel now has a Set button. When clicked, it sends a changeColor:message down the responder chain. See the NSColorPanel documentation for details.


NSFont

The systemFontOfSize:and boldSystemFontOfSize:methods have been deprecated in favor of the other factory methods returning user-chosen fonts. The function NSConvertGlyphsToPackedGlyphs()was added to allow you to convert an array of NSGlyphs to "packed" glyphs, suitable for passing to PostScript.


NSImage and NSBitmapImageRep

NSImage and NSBitmapImageRep can now read GIF, JPEG, and PNG images directly (that is, without the aid of filter services). JPEG and PNG writing is also supported; GIF writing is planned for a future release. Some APIs were added to NSBitmapImageRep to provide support for features found in these image file types.


NSBezierPath and NSAffineTransform

These two classes help provide a more complete abstraction in the Application Kit framework layer for graphics operations. NSBezierPath enables standard operations with lines, user-defined paths, and arrays of glyphs, such as stroking, filling, and clipping. It also provides simple bounds computation and hit detection methods. NSAffineTransform provides an abstraction for the graphics transformation matrix.


NSGraphicsContext

The abstract superclass for NSDPSContext, this class provides methods to save and restore the graphics state and to change the current graphics context.


NSGraphics (Java)

NSGraphics has three class methods that do not work correctly in DR2 (calling them has no effect):
fillRectList(NSRect[])
fillRectListWithColors(NSRect[], NSColor[])
clipRectList(NSRect[])
Instead of these methods, use the corresponding "inRange" methods:
fillRectList(rects) ==>
fillRectListInRange(rects, new NSRange(0, rects.length))
fillRectListWithColors(rects, color) ==>
fillRectListWithColorsInRange(rects, colors, new NSRange(0, rects.length))
clipRectList(rects) ==>
clipRectListInRange(rects, new NSRange(0, rects.length))

NSSplitView

The look and feel of the split view has changed significantly. There's no dimple, the split bar is thinner, and you get a resize image when the cursor is over it. You should use the method dividerThicknessto determine the correct thickness of the bar.


NSScreen

The new method visibleFramesupplies the usable region (without menu or task bar regions) of a given screen.


Menu and Pop-up Button Classes

Menus and pop-up buttons have changed significantly since OpenStep 4.2. In 4.2, NSMenu and NSMenuItem claimed they were NSObject subclasses, but they were actually subclasses of NSPanel and NSButtonCell. Although the compiler would warn about panel or cell messages being sent to these objects, they would perform as required at run time. In the new implementation, NSMenu and NSMenuItem are true subclasses of NSObject. If your code is sending messages to these objects&emdashwhich assume inheritance from NSPanel and NSButtonCell&emdashit will no longer work.

NSMenu and NSMenuItem include new APIs and functionality. NSMenuItems may now have titles, key equivalents, images, and state images. NSMenus have a platform-specific menu representation that is in charge of presenting the menu to the user and allowing the user to interact with it. On Mach, the menu representation is an NSMenuView. NSMenuView allows much leeway in the way a menu works and looks. An NSMenuView uses NSMenuItemCells to draw its items. On Windows the menu representation class is currently private (NSMenu's menuRepresentationmethod will return nil).

The NSMenuItem protocol has been deprecated in favor of the NSMenuItem class. Use the class instead of the protocol, which will be dropped from the Application Kit in a future release. There is now a public NSPopUpButtonCell class. See the Application Kit reference documentation for details of the new APIs.

Some planned features are not yet implemented, such as tear offs and key-equivalent overrides. You should not have to do anything special to prepare your application for these coming features. Context menus are supported in the Developer Release, but only for systems with two-button mice. Support will be added in a later release support for Control-click context menus. Your code should not have to change, but you should be aware that using the control key for your own special mouse features is probably not a good idea since that modifier key will soon have another meaning.



NSSlider

Sliders now support tick marks that identify specific values on the slider continuum. Clicking these tick marks returns the represented value.


NSTextView

NSTextView objects can now read HTML files. A delegate method is provided for following HTML links.

Delegate methods for clicking on cells have been augmented with an argument to specify the character index of the click; for instance,textView:clickedOnCell:inRect:atIndex:instead of textView:clickedOnCell:inRect:. The old delegate methods will continue to work, but you should plan to replace them with the new ones.

The text system now treats control-L ("form feed") as a container break character. A control-L forces the layout to continue onto the next container. However, the text system also tries to recognize the infinitely-growing container case (which is the usual situation in applications such as TextEdit and Project Builder), and ignores the control-L in these cases.


NSApplication

On non-Windows platforms, an application can now choose to quit when the last window is closed. If the application delegate responds to applicationShouldTerminateAfterLastWindowClosed:by returning YES, the application is sent a terminate:message when the last window is closed.

On Windows systems there has been no change. If the last window of an application is closed, and if the window contained the application menu, the application is sent the terminate:message by default. The delegate can prevent this by responding NO to applicationShouldTerminateAfterLastWindowClosed:.


NSWindow

Instead of miniaturizing, windows now use a feature called WindowShading: when the user clicks the appropriate window control, the window's content view disappears and just the title bar remains (this can be toggled back to the original state). Windows also have a zoom button, which switches a window between a standard (size-to-fit) size and a user size. The standard size can be set by calls to the delegate.

A document icon in the title bar gives access to the document represented by the window; users can drag and drop the document directly (this replaces the "Alternate-drag from the miniaturize button" model of OPENSTEP 4.2).


NSView

Two new methods in NSView, didAddSubview:and willRemoveSubview:, provide ways to detect subview list changes.


NSCell and NSButtonCell

These classes now support mixed-state cells. You can enable this feature with thesetAllowsMixedState:method, which allows the cell to be in NSMixedState mode in addition to NSOnState and NSOffState. In addition, various bezel styles have been added to support the range of button styles available on the Mac:

- NSRoundedBezelStyle
- NSRegularSquareBezelStyle
- NSThickSquareBezelStyle
- NSThickerSquareBezelStyle

(Although the header file refers to NSNeXTBezelStyle, NSPushButtonBezelStyle, NSSmallIconButtonBezelStyle, NSMediumIconButtonBezelStyle, and NSLargeIconButtonBezelStyle, these styles are obsolete and should not be used.)


Java

The Developer release contains an alpha version of the Java APIs for the Yellow Box. By using these APIs you can access virtually all classes and protocols of the Application Kit and Foundation frameworks. However, since this is an alpha version, these APIs are not yet complete and will most likely change before the next release.


Interface Style

The constant NSMacintoshInterfaceStyle has been added to represent the MacOS user interface. NSNextStepInterfaceStyle has been removed.

When creating resources, use the suffixes "-macintosh" and "-windows" to indicate any resources that are specific to a particular interface style. The base resource must be available (for instance, foo.nib); all the other interface-style specific ones (such as foo-windows.nib) are optional. This is a feature of NSBundle, and will work with any resource, not just nibs.



Summary of Changes Between NextStep 3.3 and OpenStep 4.2

This section is provided as a quick guide to developers converting applications from NextStep 3.x to the Yellow Box. OpenStep 4.2 was the last release shipped by NeXT before the Apple purchase.

Changes between NextStep 3.3 and OpenStep 4.0

OpenStep: Release 4.0 brings numerous API changes to the AppKit relative to Release 3.3. Tools and scripts provided to convert a 3.x application to OpenStep are included with the 4.x releases, in /NextLibrary/Documentation/NextDev/Conversion/ConversionGuide....

New Text System: Release 4.0 includes a new text system composed of several different classes: NSTextView (front-end UI), NSTextStorage and NSAttributedString (back-end text storage), NSLayoutManager (management of text layout process and info), and NSTextContainer (description of text flow areas). These classes provide an open, powerful interface and allow text editing in multiple languages, using the Unicode standard.

FileWrapper: NSFileWrapper, a new class, provides support for the concept of a document wrapper (like a .rtfd or ....nib). It handles reading and writing file packages in the file system as well as serializing them for use with the Pasteboard.

TableView: DBKit's table view class has been completely rewritten and moved into the AppKit as NSTableView. All four classes making up the new TableView are public and fully subclassable.

Keyboard UI: Keyboard access is now provided to most of the controls in the AppKit.

Formatting and Validation: Cells may now be assigned arbitrary object values, which are converted into presentation strings by associated formatter objects. This allows the developer to directly set an NSDate, for instance, as the value of a cell. The cell's associated date formatter will present a localized string representation of the date to the user. The formatter objects, along with control delegates, can also perform validation on user-entered data, thereby restricting entries to valid ranges or quantities.

Rich Text in Cells: NSCell and subclasses can now display and edit rich text. The rich text is specified via instances of NSAttributedString. The new formatting/validation API also includes support for attributed strings.

RulerView: NSRulerView is designed as a general-purpose ruler that can be associated with any scroll view and used by any view that's in the scroll view. It supports both horizontal and vertical rulers, allows arbitrary markers along the rule, and can accept an accessory view.

System Colors: New API has been added to access system-defined colors, such as the color of buttons, controls, text and text selection colors. On Windows, where the user can change the system colors at any point, these colors will change at runtime to match the user's selection.

Image: NSImage now understands the bmp, ico, and cur image formats. ico and cur files with multiple images will be loaded as images with multiple representations. Typically these representations will have different sizes (unlike multiple-representation tiffs, which have different depths); by default, NSImage will choose the largest image when compositing.

NSApplicationMain: The AppKit now provides a function NSApplicationMain() to take care of the initialization and startup of your application. This function is declared in NSApplication.h.

ObjectLinks: ObjectLinks have been removed from the OpenStep specification, and in general the feature is not supported in OpenStep for Mach or Windows.

Help System: The AppKit's Help API has changed significantly. NSHelpPanel has been obsoleted in favor of a new class, NSHelpManager, which provides a more platform-independent approach to presenting both context-sensitive and comprehensive help.

Changes between OpenStep 4.0 and OpenStep 4.1

ComboBox: NSComboBox class has been added to the Application Kit. It offers functionality that is similar to the Combo Box control used in the Microsoft Windows user interface.

Splash Screen: OpenStep for Windows now provides support for a "splash" screen in applications; this is basically a panel that comes up with a static image as the application is launched. To use this feature, simply provide an 8-bit uncompressed bitmap (.bmp) image named Splash.bmpas a resource in your application. You can make it localizable if you wish (thus the image can be either in appname.app/Resources/or appname.app/Resources/language.lproj/)

NSApplication: By default, on OpenStep for Windows, only a single copy of an application will be launched. If you wish to run multiple copies, you should use specify a value of NO to the -NSUseRunningCopycommand line option. In addition, all command-line options that are not defaults options (meaning a pair of arguments where the first one starts with a "-") are now treated as file names to be opened, as if they were prefixed with -NSOpen.As a result of these two changes, you can now associate documents with OpenStep applications on Windows simply by specifying the location of the application. The default command line provided by the Explorer suffices to open documents and also to connect to a running copy of the application, if there is one.

Window edited status: In OpenStep for Windows, an asterisk in a window's title bar indicates that the associated document has been edited.

Tracking rectangles: Tracking rectangles are now implemented on Windows.

NSWindow frame vs content rect: On Windows, the frameRect and contentRect of an NSWindow are currently the same size. Thus the frameRect of an NSWindow does not include the title bar, menu bar, resize border, and so on (but does on Mach). Also, the contentView while a window is miniaturized is an NSImageView, not the original contentView. The contentView is restored when the window is deminiaturized.

NSTextView: On Windows, to allow entering a character without an appropriate keyboard, you can now use the Alternatekey in conjunction with the digit keys from the keypad. While holding down the Alternate key, type the index of the desired character in the encoding of the current font (in most cases this will be the NEXTSTEP encoding). The appropriate character will be inserted into the text when the Alternate key is released.

Changes between OpenStep 4.1 and OpenStep 4.2

SplitView: NSSplitView now supports horizontal as well vertical splits.

ToolTips: It's now possible to add "tooltips" (short help messages that pop up as the user holds the mouse cursor over an item) to views. You can do this programmatically or by using Interface Builder's Help panel.

Text Hyphenation and Justification: The text object now supports full justification and hyphenation, with a fairly basic API.

ComboBox cell: There is now a public NSComboBoxCell class. This feature allows you to use combo boxes in table views, among other places.

Hiding applications on Windows: Support for the "hide application" command has been added to OpenStep for Windows. The default menu item for this is Minimize All in the Windows menu (with Control-h as the key equivalent). The Application Kit adds this item automatically if it is not in the menu.

CMYK archiving problem: A bug in decodeNXColorthat caused CMYK colors from 3.x archives to be read incorrectly in 4.0 and 4.1 has been fixed. (The colors were way off base; instead of C, M, Y, K, the values 1-C, 1-M, 1-Y, and 1-K were used.)



Copyright © 2017 Apple Inc. All Rights Reserved.