PATH Documentation > Release Notes
Mac OS X Developer Release Notes:
Cocoa Application Framework (10.4 and Earlier)
This document contains the release notes for Mac OS X 10.4, its updates, 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 X 10.4
New features in Tiger
The following are some of the new features in AppKit, Foundation, and related areas in Tiger.
AppKit (these are described in greater detail further below in this file):
- New UI element NSDatePicker
- New UI element NSTokenField
- New UI element NSLevelIndicator
- New animation timing classes NSAnimation and NSViewAnimation
- New class NSPersistentDocument, a CoreData-based NSDocument subclass
- New class NSTreeController
- New class NSColorSpace (Added since WWDC)
- New classes for list and table support in NSTextView
- Improved HTML import/export support in NSTextView
- Restructured NSFont and NSFontDescriptor classes
- Base writing direction support in text and controls
- Support for resolution independent UI
- NSDocument support for autosaving and better error handling
- NSResponder-based error presentation (Added since WWDC)
- Support in NSEvent for native tablet events
- Improvements in accessibility
- NSBitmapImageRep support for alternate bitmap formats and types
- NSTableView autoresizing, custom tooltip, and variable row height support
- NSGraphicsContext bitmap support
- NSWindow optimized live resize support
- NSView drawing redirection
- Automatic page headers/footers in printouts (Added since WWDC)
- CoreImage API support (Added since WWDC)
Foundation (these are described in the Foundation release notes):
- New class NSMetadataQuery for high level Spotlight metadata query support
- New set of classes for XML document management
- New class NSLocale
- New class NSIndexPath for representing sequence of indexes
- New methods in NSString to replace deprecated cString APIs and return NSErrors on read/write
- New methods in NSData to return NSErrors on read/write
- NSError enhancements, including richer set of user-presentable error messages (Added since WWDC)
- Key-Value Coding and Observing for Sets (Added since WWDC)
- Enhanced functionality in NSDateFormatter and NSNumberFormatter
- "sdef" file support in scripting
Some of the other new Mac OS X APIs to be aware of:
- CoreData, new framework for object life cycle management (CoreData is part of the Cocoa umbrella framework)
- QTKit, containing Cocoa classes for QuickTime
- PDFKit, classes for PDF documents
- QuartzComposer, APIs for parameterized animations and visualizations
- CoreImage, APIs for GPU based image processing
- InstantMessage, presence APIs
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 modifer 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 MacOS 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 MacOS 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 MacOS 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 MacOS 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]).
These cases are described in these and in Foundation release notes.
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 MacOS 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 MacOS 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 MacOS 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 MacOS 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 MacOS 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 MacOS 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 MacOS 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 MacOS 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 © 2006 Apple Computer, Inc.