Implement CSS cursor support for Mac OS X. b=286304 r=josh

This commit is contained in:
lordpixel@mac.com 2010-03-11 11:44:31 -05:00
parent d162651fc5
commit 21a3877edf
7 changed files with 336 additions and 114 deletions

View File

@ -977,8 +977,7 @@ NS_IMETHODIMP nsChildView::SetCursor(nsCursor aCursor)
return NS_OK; // Don't change the cursor during dragging.
nsBaseWidget::SetCursor(aCursor);
[[nsCursorManager sharedInstance] setCursor: aCursor];
return NS_OK;
return [[nsCursorManager sharedInstance] setCursor:aCursor];
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
@ -987,7 +986,12 @@ NS_IMETHODIMP nsChildView::SetCursor(nsCursor aCursor)
NS_IMETHODIMP nsChildView::SetCursor(imgIContainer* aCursor,
PRUint32 aHotspotX, PRUint32 aHotspotY)
{
return nsBaseWidget::SetCursor(aCursor, aHotspotX, aHotspotY);
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
nsBaseWidget::SetCursor(aCursor, aHotspotX, aHotspotY);
return [[nsCursorManager sharedInstance] setCursorWithImage:aCursor hotSpotX:aHotspotX hotSpotY:aHotspotY];
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
#pragma mark -

View File

@ -45,6 +45,7 @@
#include "nsRect.h"
#include "nsObjCExceptions.h"
#include "imgIContainer.h"
class nsIWidget;
@ -130,6 +131,37 @@ class nsCocoaUtils
static void PrepareForNativeAppModalDialog();
static void CleanUpAfterNativeAppModalDialog();
// 3 utility functions to go from a frame of imgIContainer to CGImage and then to NSImage
// Convert imgIContainer -> CGImageRef, caller owns result
/** Creates a <code>CGImageRef</code> from a frame contained in an <code>imgIContainer</code>.
Copies the pixel data from the indicated frame of the <code>imgIContainer</code> into a new <code>CGImageRef</code>.
The caller owns the <code>CGImageRef</code>.
@param aImage the image to extract a frame from
@param aWhichFrame the frame to extract (see imgIContainer FRAME_*)
@param aResult the resulting CGImageRef
@return NS_OK if the conversion worked, NS_ERROR_FAILURE otherwise
*/
static nsresult CreateCGImageFromImageContainer(imgIContainer *aImage, PRUint32 aWhichFrame, CGImageRef *aResult);
/** Creates a Cocoa <code>NSImage</code> from a <code>CGImageRef</code>.
Copies the pixel data from the <code>CGImageRef</code> into a new <code>NSImage</code>.
The caller owns the <code>NSImage</code>.
@param aInputImage the image to convert
@param aResult the resulting NSImage
@return NS_OK if the conversion worked, NS_ERROR_FAILURE otherwise
*/
static nsresult CreateNSImageFromCGImage(CGImageRef aInputImage, NSImage **aResult);
/** Creates a Cocoa <code>NSImage</code> from a frame of an <code>imgIContainer</code>.
Combines the two methods above. The caller owns the <code>NSImage</code>.
@param aImage the image to extract a frame from
@param aWhichFrame the frame to extract (see imgIContainer FRAME_*)
@param aResult the resulting NSImage
@return NS_OK if the conversion worked, NS_ERROR_FAILURE otherwise
*/
static nsresult CreateNSImageFromImageContainer(imgIContainer *aImage, PRUint32 aWhichFrame, NSImage **aResult);
};
#endif // nsCocoaUtils_h_

View File

@ -38,6 +38,7 @@
*
* ***** END LICENSE BLOCK ***** */
#include "gfxImageSurface.h"
#include "nsCocoaUtils.h"
#include "nsMenuBarX.h"
#include "nsCocoaWindow.h"
@ -243,3 +244,84 @@ void nsCocoaUtils::CleanUpAfterNativeAppModalDialog()
NS_OBJC_END_TRY_ABORT_BLOCK;
}
nsresult nsCocoaUtils::CreateCGImageFromImageContainer(imgIContainer *aImage, PRUint32 aWhichFrame, CGImageRef *aResult)
{
nsRefPtr<gfxImageSurface> frame;
nsresult rv = aImage->CopyFrame(aWhichFrame,
imgIContainer::FLAG_SYNC_DECODE,
getter_AddRefs(frame));
if (NS_FAILED(rv) || !frame) {
return NS_ERROR_FAILURE;
}
PRInt32 width = frame->Width();
PRInt32 stride = frame->Stride();
PRInt32 height = frame->Height();
if ((stride % 4 != 0) || (height < 1) || (width < 1)) {
return NS_ERROR_FAILURE;
}
// Create a CGImageRef with the bits from the image, taking into account
// the alpha ordering and endianness of the machine so we don't have to
// touch the bits ourselves.
CGDataProviderRef dataProvider = ::CGDataProviderCreateWithData(NULL,
frame->Data(),
stride * height,
NULL);
CGColorSpaceRef colorSpace = ::CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
*aResult = ::CGImageCreate(width,
height,
8,
32,
stride,
colorSpace,
kCGBitmapByteOrder32Host | kCGImageAlphaFirst,
dataProvider,
NULL,
0,
kCGRenderingIntentDefault);
::CGColorSpaceRelease(colorSpace);
::CGDataProviderRelease(dataProvider);
return *aResult ? NS_OK : NS_ERROR_FAILURE;
}
nsresult nsCocoaUtils::CreateNSImageFromCGImage(CGImageRef aInputImage, NSImage **aResult)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
PRInt32 width = ::CGImageGetWidth(aInputImage);
PRInt32 height = ::CGImageGetHeight(aInputImage);
NSRect imageRect = ::NSMakeRect(0.0, 0.0, width, height);
// Create a new image to receive the Quartz image data.
*aResult = [[NSImage alloc] initWithSize:imageRect.size];
[*aResult lockFocus];
// Get the Quartz context and draw.
CGContextRef imageContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
::CGContextDrawImage(imageContext, *(CGRect*)&imageRect, aInputImage);
[*aResult unlockFocus];
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
nsresult nsCocoaUtils::CreateNSImageFromImageContainer(imgIContainer *aImage, PRUint32 aWhichFrame, NSImage **aResult)
{
CGImageRef imageRef = NULL;
nsresult rv = nsCocoaUtils::CreateCGImageFromImageContainer(aImage, aWhichFrame, &imageRef);
if (NS_FAILED(rv) || !imageRef) {
return NS_ERROR_FAILURE;
}
rv = nsCocoaUtils::CreateNSImageFromCGImage(imageRef, aResult);
if (NS_FAILED(rv) || !aResult) {
return NS_ERROR_FAILURE;
}
::CGImageRelease(imageRef);
return NS_OK;
}

View File

@ -50,7 +50,7 @@
{
@private
NSMutableDictionary *mCursors;
nsCursor mCurrentCursor;
nsMacCursor *mCurrentMacCursor;
}
/*! @method setCursor:
@ -59,7 +59,18 @@
Resources associated with the previous cursor are cleaned up.
@param aCursor the cursor to use
*/
- (void) setCursor: (nsCursor) aCursor;
- (nsresult) setCursor: (nsCursor) aCursor;
/*! @method setCursorWithImage:hotSpotX:hotSpotY:
@abstract Sets the current cursor to a custom image
@discussion Sets the current cursor to the cursor given by the aCursorImage argument.
Resources associated with the previous cursor are cleaned up.
@param aCursorImage the cursor image to use
@param aHotSpotX the x coordinate of the cursor's hotspot
@param aHotSpotY the y coordinate of the cursor's hotspot
*/
- (nsresult) setCursorWithImage: (imgIContainer*) aCursorImage hotSpotX: (PRUint32) aHotspotX hotSpotY: (PRUint32) aHotspotY;
/*! @method sharedInstance
@abstract Get the Singleton instance of the cursor manager.

View File

@ -35,12 +35,16 @@
*
* ***** END LICENSE BLOCK ***** */
#include "imgIContainer.h"
#include "nsCocoaUtils.h"
#include "nsCursorManager.h"
#include "nsObjCExceptions.h"
#include <math.h>
static nsCursorManager *gInstance;
static NSArray* sSpinCursorFrames = nil;
static NSArray *sSpinCursorFrames = nil;
static imgIContainer *sCursorImgContainer = nsnull;
static const nsCursor sCustomCursor = eCursorCount;
/*! @category nsCursorManager(PrivateMethods)
Private methods for the cursor manager class.
@ -56,6 +60,15 @@ static NSArray* sSpinCursorFrames = nil;
*/
- (nsMacCursor *) getCursor: (nsCursor) aCursor;
/*! @method setMacCursor:
@abstract Set the current Mac native cursor
@discussion Sets the current cursor - this routine is what actually causes the cursor to change.
The argument is retained and the old cursor is released.
@param aMacCursor the cursor to set
@result NS_OK
*/
- (nsresult) setMacCursor: (nsMacCursor*) aMacCursor;
/*! @method createCursor:
@abstract Create a Mac native representation of a cursor.
@discussion Creates a version of the Mac native representation of this cursor
@ -101,7 +114,7 @@ static NSArray* sSpinCursorFrames = nil;
NS_OBJC_END_TRY_ABORT_BLOCK;
}
+ (nsMacCursor *) createCursor: (enum nsCursor) aCursor
+ (nsMacCursor *) createCursor: (enum nsCursor) aCursor
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
@ -109,100 +122,100 @@ static NSArray* sSpinCursorFrames = nil;
{
SEL cursorSelector;
case eCursor_standard:
return [nsMacCursor cursorWithCursor: [NSCursor arrowCursor]];
return [nsMacCursor cursorWithCursor:[NSCursor arrowCursor] type:aCursor];
case eCursor_wait:
case eCursor_spinning:
return [nsMacCursor cursorWithFrames: sSpinCursorFrames];
return [nsMacCursor cursorWithFrames:sSpinCursorFrames type:aCursor];
case eCursor_select:
return [nsMacCursor cursorWithCursor: [NSCursor IBeamCursor]];
return [nsMacCursor cursorWithCursor:[NSCursor IBeamCursor] type:aCursor];
case eCursor_hyperlink:
return [nsMacCursor cursorWithCursor: [NSCursor pointingHandCursor]];
return [nsMacCursor cursorWithCursor:[NSCursor pointingHandCursor] type:aCursor];
case eCursor_crosshair:
return [nsMacCursor cursorWithCursor: [NSCursor crosshairCursor]];
return [nsMacCursor cursorWithCursor:[NSCursor crosshairCursor] type:aCursor];
case eCursor_move:
return [nsMacCursor cursorWithCursor: [NSCursor openHandCursor]];
return [nsMacCursor cursorWithCursor:[NSCursor openHandCursor] type:aCursor];
case eCursor_help:
return [nsMacCursor cursorWithImageNamed: @"help" hotSpot: NSMakePoint(1,1)];
return [nsMacCursor cursorWithImageNamed:@"help" hotSpot:NSMakePoint(1,1) type:aCursor];
case eCursor_copy:
cursorSelector = @selector(dragCopyCursor);
return [nsMacCursor cursorWithCursor: [NSCursor respondsToSelector: cursorSelector] ?
[NSCursor performSelector: cursorSelector] :
[NSCursor arrowCursor]];
return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector] ?
[NSCursor performSelector:cursorSelector] :
[NSCursor arrowCursor] type:aCursor];
case eCursor_alias:
cursorSelector = @selector(dragLinkCursor);
return [nsMacCursor cursorWithCursor: [NSCursor respondsToSelector: cursorSelector] ?
[NSCursor performSelector: cursorSelector] :
[NSCursor arrowCursor]];
return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector] ?
[NSCursor performSelector:cursorSelector] :
[NSCursor arrowCursor] type:aCursor];
case eCursor_context_menu:
cursorSelector = @selector(contextualMenuCursor);
return [nsMacCursor cursorWithCursor: [NSCursor respondsToSelector: cursorSelector] ?
[NSCursor performSelector: cursorSelector] :
[NSCursor arrowCursor]];
return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector] ?
[NSCursor performSelector:cursorSelector] :
[NSCursor arrowCursor] type:aCursor];
case eCursor_cell:
return [nsMacCursor cursorWithCursor: [NSCursor crosshairCursor]];
return [nsMacCursor cursorWithCursor:[NSCursor crosshairCursor] type:aCursor];
case eCursor_grab:
return [nsMacCursor cursorWithCursor: [NSCursor openHandCursor]];
return [nsMacCursor cursorWithCursor:[NSCursor openHandCursor] type:aCursor];
case eCursor_grabbing:
return [nsMacCursor cursorWithCursor: [NSCursor closedHandCursor]];
return [nsMacCursor cursorWithCursor:[NSCursor closedHandCursor] type:aCursor];
case eCursor_zoom_in:
return [nsMacCursor cursorWithImageNamed: @"zoomIn" hotSpot: NSMakePoint(6,6)];
return [nsMacCursor cursorWithImageNamed:@"zoomIn" hotSpot:NSMakePoint(6,6) type:aCursor];
case eCursor_zoom_out:
return [nsMacCursor cursorWithImageNamed: @"zoomOut" hotSpot: NSMakePoint(6,6)];
return [nsMacCursor cursorWithImageNamed:@"zoomOut" hotSpot:NSMakePoint(6,6) type:aCursor];
case eCursor_vertical_text:
return [nsMacCursor cursorWithImageNamed: @"vtIBeam" hotSpot: NSMakePoint(7,8)];
return [nsMacCursor cursorWithImageNamed:@"vtIBeam" hotSpot:NSMakePoint(7,8) type:aCursor];
case eCursor_all_scroll:
return [nsMacCursor cursorWithCursor: [NSCursor openHandCursor]];;
return [nsMacCursor cursorWithCursor:[NSCursor openHandCursor] type:aCursor];
case eCursor_not_allowed:
case eCursor_no_drop:
cursorSelector = @selector(operationNotAllowedCursor);
return [nsMacCursor cursorWithCursor: [NSCursor respondsToSelector: cursorSelector] ?
[NSCursor performSelector: cursorSelector] :
[NSCursor arrowCursor]];
return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector] ?
[NSCursor performSelector:cursorSelector] :
[NSCursor arrowCursor] type:aCursor];
// Resize Cursors:
//North
// North
case eCursor_n_resize:
return [nsMacCursor cursorWithCursor: [NSCursor resizeUpCursor]];
//North East
return [nsMacCursor cursorWithCursor:[NSCursor resizeUpCursor] type:aCursor];
// North East
case eCursor_ne_resize:
return [nsMacCursor cursorWithImageNamed: @"sizeNE" hotSpot: NSMakePoint(8,7)];
//East
case eCursor_e_resize:
return [nsMacCursor cursorWithCursor: [NSCursor resizeRightCursor]];
//South East
return [nsMacCursor cursorWithImageNamed:@"sizeNE" hotSpot:NSMakePoint(8,7) type:aCursor];
// East
case eCursor_e_resize:
return [nsMacCursor cursorWithCursor:[NSCursor resizeRightCursor] type:aCursor];
// South East
case eCursor_se_resize:
return [nsMacCursor cursorWithImageNamed: @"sizeSE" hotSpot: NSMakePoint(8,8)];
//South
return [nsMacCursor cursorWithImageNamed:@"sizeSE" hotSpot:NSMakePoint(8,8) type:aCursor];
// South
case eCursor_s_resize:
return [nsMacCursor cursorWithCursor: [NSCursor resizeDownCursor]];
//South West
return [nsMacCursor cursorWithCursor:[NSCursor resizeDownCursor] type:aCursor];
// South West
case eCursor_sw_resize:
return [nsMacCursor cursorWithImageNamed: @"sizeSW" hotSpot: NSMakePoint(6,8)];
//West
return [nsMacCursor cursorWithImageNamed:@"sizeSW" hotSpot:NSMakePoint(6,8) type:aCursor];
// West
case eCursor_w_resize:
return [nsMacCursor cursorWithCursor: [NSCursor resizeLeftCursor]];
//North West
return [nsMacCursor cursorWithCursor:[NSCursor resizeLeftCursor] type:aCursor];
// North West
case eCursor_nw_resize:
return [nsMacCursor cursorWithImageNamed: @"sizeNW" hotSpot: NSMakePoint(7,7)];
//North & South
return [nsMacCursor cursorWithImageNamed:@"sizeNW" hotSpot:NSMakePoint(7,7) type:aCursor];
// North & South
case eCursor_ns_resize:
return [nsMacCursor cursorWithCursor: [NSCursor resizeUpDownCursor]];
//East & West
return [nsMacCursor cursorWithCursor:[NSCursor resizeUpDownCursor] type:aCursor];
// East & West
case eCursor_ew_resize:
return [nsMacCursor cursorWithCursor: [NSCursor resizeLeftRightCursor]];
//North East & South West
return [nsMacCursor cursorWithCursor:[NSCursor resizeLeftRightCursor] type:aCursor];
// North East & South West
case eCursor_nesw_resize:
return [nsMacCursor cursorWithImageNamed: @"sizeNESW" hotSpot: NSMakePoint(8,8)];
//North West & South East
return [nsMacCursor cursorWithImageNamed:@"sizeNESW" hotSpot:NSMakePoint(8,8) type:aCursor];
// North West & South East
case eCursor_nwse_resize:
return [nsMacCursor cursorWithImageNamed: @"sizeNWSE" hotSpot: NSMakePoint(8,8)];
//Column Resize
return [nsMacCursor cursorWithImageNamed:@"sizeNWSE" hotSpot:NSMakePoint(8,8) type:aCursor];
// Column Resize
case eCursor_col_resize:
return [nsMacCursor cursorWithImageNamed: @"colResize" hotSpot: NSMakePoint(8,8)];
//Row Resize
return [nsMacCursor cursorWithImageNamed:@"colResize" hotSpot:NSMakePoint(8,8) type:aCursor];
// Row Resize
case eCursor_row_resize:
return [nsMacCursor cursorWithImageNamed: @"rowResize" hotSpot: NSMakePoint(8,8)];
return [nsMacCursor cursorWithImageNamed:@"rowResize" hotSpot:NSMakePoint(8,8) type:aCursor];
default:
return [nsMacCursor cursorWithCursor: [NSCursor arrowCursor]];
return [nsMacCursor cursorWithCursor:[NSCursor arrowCursor] type:aCursor];
}
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
@ -220,43 +233,100 @@ static NSArray* sSpinCursorFrames = nil;
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
}
- (void) setCursor: (enum nsCursor) aCursor
- (nsresult) setCursor: (enum nsCursor) aCursor
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
// Some plugins mess with our cursors and set a cursor that even
// [NSCursor currentCursor] doesn't know about. In case that happens, just
// reset the state.
[[NSCursor currentCursor] set];
nsMacCursor* currentCursor = [self getCursor: mCurrentCursor];
if (aCursor != mCurrentCursor || ![currentCursor isSet]) {
[currentCursor unset];
[[self getCursor: aCursor] set];
}
if (mCurrentCursor != aCursor) {
nsCursor oldType = [mCurrentMacCursor type];
if (oldType != aCursor) {
if (aCursor == eCursor_none) {
[NSCursor hide];
} else if (mCurrentCursor == eCursor_none) {
} else if (oldType == eCursor_none) {
[NSCursor unhide];
}
}
[self setMacCursor:[self getCursor:aCursor]];
mCurrentCursor = aCursor;
// if a custom cursor was previously set, release sCursorImgContainer
if (oldType == sCustomCursor) {
NS_IF_RELEASE(sCursorImgContainer);
}
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
NS_OBJC_END_TRY_ABORT_BLOCK;
- (nsresult) setMacCursor: (nsMacCursor*) aMacCursor
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
if (mCurrentMacCursor != aMacCursor || ![mCurrentMacCursor isSet]) {
[aMacCursor retain];
[mCurrentMacCursor unset];
[aMacCursor set];
[mCurrentMacCursor release];
mCurrentMacCursor = aMacCursor;
}
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
- (nsresult) setCursorWithImage: (imgIContainer*) aCursorImage hotSpotX: (PRUint32) aHotspotX hotSpotY: (PRUint32) aHotspotY
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
// As the user moves the mouse, this gets called repeatedly with the same aCursorImage
if (sCursorImgContainer == aCursorImage && mCurrentMacCursor) {
[self setMacCursor:mCurrentMacCursor];
return NS_OK;
}
[[NSCursor currentCursor] set];
PRInt32 width = 0, height = 0;
aCursorImage->GetWidth(&width);
aCursorImage->GetHeight(&height);
// prevent DoS attacks
if (width > 128 || height > 128) {
return NS_OK;
}
NSImage *cursorImage;
nsresult rv = nsCocoaUtils::CreateNSImageFromImageContainer(aCursorImage, imgIContainer::FRAME_FIRST, &cursorImage);
if (NS_FAILED(rv) || !cursorImage) {
return NS_ERROR_FAILURE;
}
// if the hotspot is nonsensical, make it 0,0
aHotspotX = (aHotspotX < 0 || aHotspotX > (PRUint32) width - 1) ? 0 :aHotspotX;
aHotspotY = (aHotspotY < 0 || aHotspotY > (PRUint32) height - 1) ? 0 :aHotspotY;
NSPoint hotSpot = ::NSMakePoint(aHotspotX, aHotspotY);
[self setMacCursor:[nsMacCursor cursorWithCursor:[[NSCursor alloc] initWithImage:cursorImage hotSpot:hotSpot] type:sCustomCursor]];
[cursorImage release];
NS_IF_RELEASE(sCursorImgContainer);
sCursorImgContainer = aCursorImage;
NS_ADDREF(sCursorImgContainer);
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
- (nsMacCursor *) getCursor: (enum nsCursor) aCursor
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
nsMacCursor * result = [mCursors objectForKey: [NSNumber numberWithInt: aCursor]];
nsMacCursor * result = [mCursors objectForKey:[NSNumber numberWithInt:aCursor]];
if (!result) {
result = [nsCursorManager createCursor: aCursor];
[mCursors setObject: result forKey: [NSNumber numberWithInt: aCursor]];
result = [nsCursorManager createCursor:aCursor];
[mCursors setObject:result forKey:[NSNumber numberWithInt:aCursor]];
}
return result;
@ -267,8 +337,10 @@ static NSArray* sSpinCursorFrames = nil;
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
[[self getCursor: mCurrentCursor] unset];
[mCursors release];
[mCurrentMacCursor unset];
[mCurrentMacCursor release];
[mCursors release];
NS_IF_RELEASE(sCursorImgContainer);
[super dealloc];
NS_OBJC_END_TRY_ABORT_BLOCK;

View File

@ -37,6 +37,7 @@
#define nsMacCursor_h_
#import <Cocoa/Cocoa.h>
#import "nsIWidget.h"
/*! @class nsMacCursor
@abstract Represents a native Mac cursor.
@ -49,6 +50,7 @@
@private
NSTimer *mTimer;
@protected
nsCursor mType;
int mFrameCounter;
}
@ -56,11 +58,12 @@
@abstract Create a cursor by specifying a Cocoa <code>NSCursor</code>.
@discussion Creates a cursor representing the given Cocoa built-in cursor.
@param aCursor the <code>NSCursor</code> to use
@param aType the corresponding <code>nsCursor</code> constant
@result an autoreleased instance of <code>nsMacCursor</code> representing the given <code>NSCursor</code>
*/
+ (nsMacCursor *) cursorWithCursor: (NSCursor *) aCursor;
+ (nsMacCursor *) cursorWithCursor: (NSCursor *) aCursor type: (nsCursor) aType;
/*! @method cursorWithImageNamed:hotSpot:
/*! @method cursorWithImageNamed:hotSpot:type:
@abstract Create a cursor by specifying the name of an image resource to use for the cursor and a hotspot.
@discussion Creates a cursor by loading the named image using the <code>+[NSImage imageNamed:]</code> method.
<p>The image must be compatible with any restrictions laid down by <code>NSCursor</code>. These vary
@ -68,19 +71,21 @@
<p>The hotspot precisely determines the point where the user clicks when using the cursor.</p>
@param aCursor the name of the image to use for the cursor
@param aPoint the point within the cursor to use as the hotspot
@param aType the corresponding <code>nsCursor</code> constant
@result an autoreleased instance of <code>nsMacCursor</code> that uses the given image and hotspot
*/
+ (nsMacCursor *) cursorWithImageNamed: (NSString *) aCursorImage hotSpot: (NSPoint) aPoint;
+ (nsMacCursor *) cursorWithImageNamed: (NSString *) aCursorImage hotSpot: (NSPoint) aPoint type: (nsCursor) aType;
/*! @method cursorWithFrames:
/*! @method cursorWithFrames:type:
@abstract Create an animated cursor by specifying the frames to use for the animation.
@discussion Creates a cursor that will animate by cycling through the given frames. Each element of the array
must be an instance of <code>NSCursor</code>
@param aCursorFrames an array of <code>NSCursor</code>, representing the frames of an animated cursor, in the
order they should be played.
@param aType the corresponding <code>nsCursor</code> constant
@result an autoreleased instance of <code>nsMacCursor</code> that will animate the given cursor frames
*/
+ (nsMacCursor *) cursorWithFrames: (NSArray *) aCursorFrames;
+ (nsMacCursor *) cursorWithFrames: (NSArray *) aCursorFrames type: (nsCursor) aType;
/*! @method cocoaCursorWithImageNamed:hotSpot:
@abstract Create a Cocoa NSCursor object with a Gecko image resource name and a hotspot point.
@ -118,6 +123,14 @@
*/
- (BOOL) isAnimated;
/** @method cursorType
@abstract Get the cursor type for this cursor
@discussion This method returns the <code>nsCursor</code> constant that corresponds to this cursor, which is
equivalent to the CSS name for the cursor.
@result The nsCursor constant corresponding to this cursor, or nsCursor's 'eCursorCount' if the cursor
is a custom cursor loaded from a URI
*/
- (nsCursor) type;
@end
#endif // nsMacCursor_h_

View File

@ -118,17 +118,19 @@
must be an instance of <code>NSCursor</code>
@param aCursorFrames an array of <code>NSCursor</code>, representing the frames of an animated cursor, in the
order they should be played.
@param aType the corresponding <code>nsCursor</code> constant
@result an instance of <code>nsCocoaCursor</code> that will animate the given cursor frames
*/
- (id) initWithFrames: (NSArray *) aCursorFrames;
- (id) initWithFrames: (NSArray *) aCursorFrames type: (nsCursor) aType;
/*! @method initWithCursor:
@abstract Create a cursor by specifying a Cocoa <code>NSCursor</code>.
@discussion Creates a cursor representing the given Cocoa built-in cursor.
@param aCursor the <code>NSCursor</code> to use
@param aType the corresponding <code>nsCursor</code> constant
@result an instance of <code>nsCocoaCursor</code> representing the given <code>NSCursor</code>
*/
- (id) initWithCursor: (NSCursor *) aCursor;
- (id) initWithCursor: (NSCursor *) aCursor type: (nsCursor) aType;
/*! @method initWithImageNamed:hotSpot:
@abstract Create a cursor by specifying the name of an image resource to use for the cursor and a hotspot.
@ -138,37 +140,38 @@
<p>The hotspot precisely determines the point where the user clicks when using the cursor.</p>
@param aCursor the name of the image to use for the cursor
@param aPoint the point within the cursor to use as the hotspot
@param aType the corresponding <code>nsCursor</code> constant
@result an instance of <code>nsCocoaCursor</code> that uses the given image and hotspot
*/
- (id) initWithImageNamed: (NSString *) aCursorImage hotSpot: (NSPoint) aPoint;
- (id) initWithImageNamed: (NSString *) aCursorImage hotSpot: (NSPoint) aPoint type: (nsCursor) aType;
@end
@implementation nsMacCursor
+ (nsMacCursor *) cursorWithCursor: (NSCursor *) aCursor
+ (nsMacCursor *) cursorWithCursor: (NSCursor *) aCursor type: (nsCursor) aType
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
return [[[nsCocoaCursor alloc] initWithCursor: aCursor] autorelease];
return [[[nsCocoaCursor alloc] initWithCursor:aCursor type:aType] autorelease];
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
}
+ (nsMacCursor *) cursorWithImageNamed: (NSString *) aCursorImage hotSpot: (NSPoint) aPoint
+ (nsMacCursor *) cursorWithImageNamed: (NSString *) aCursorImage hotSpot: (NSPoint) aPoint type: (nsCursor) aType
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
return [[[nsCocoaCursor alloc] initWithImageNamed: aCursorImage hotSpot: aPoint] autorelease];
return [[[nsCocoaCursor alloc] initWithImageNamed:aCursorImage hotSpot:aPoint type:aType] autorelease];
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
}
+ (nsMacCursor *) cursorWithFrames: (NSArray *) aCursorFrames
+ (nsMacCursor *) cursorWithFrames: (NSArray *) aCursorFrames type: (nsCursor) aType
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
return [[[nsCocoaCursor alloc] initWithFrames: aCursorFrames] autorelease];
return [[[nsCocoaCursor alloc] initWithFrames:aCursorFrames type:aType] autorelease];
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
}
@ -201,7 +204,7 @@
cursorImage = [[[NSImage alloc] initWithContentsOfFile:pathToImage] autorelease];
if (!cursorImage)
goto INIT_FAILURE;
return [[[NSCursor alloc] initWithImage: cursorImage hotSpot: aPoint] autorelease];
return [[[NSCursor alloc] initWithImage:cursorImage hotSpot:aPoint] autorelease];
INIT_FAILURE:
NS_WARNING("Problem getting path to cursor image file!");
@ -222,9 +225,9 @@ INIT_FAILURE:
if ([self isAnimated]) {
[self createTimer];
}
//if the cursor isn't animated or the timer creation fails for any reason...
// if the cursor isn't animated or the timer creation fails for any reason...
if (!mTimer) {
[self setFrame: 0];
[self setFrame:0];
}
}
@ -240,7 +243,7 @@ INIT_FAILURE:
- (int) numFrames
{
//subclasses need to override this to support animation
// subclasses need to override this to support animation
return 1;
}
@ -255,11 +258,11 @@ INIT_FAILURE:
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
if (!mTimer) {
mTimer = [[NSTimer scheduledTimerWithTimeInterval: 0.25
target: self
selector: @selector(advanceAnimatedCursor:)
userInfo: nil
repeats: YES] retain];
mTimer = [[NSTimer scheduledTimerWithTimeInterval:0.25
target:self
selector:@selector(advanceAnimatedCursor:)
userInfo:nil
repeats:YES] retain];
}
NS_OBJC_END_TRY_ABORT_BLOCK;
@ -283,7 +286,7 @@ INIT_FAILURE:
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
if ([aTimer isValid]) {
[self setFrame: [self getNextCursorFrame]];
[self setFrame:[self getNextCursorFrame]];
}
NS_OBJC_END_TRY_ABORT_BLOCK;
@ -291,7 +294,11 @@ INIT_FAILURE:
- (void) setFrame: (int) aFrameIndex
{
//subclasses need to do something useful here
// subclasses need to do something useful here
}
- (nsCursor) type {
return mType;
}
- (void) dealloc
@ -308,7 +315,7 @@ INIT_FAILURE:
@implementation nsCocoaCursor
- (id) initWithFrames: (NSArray *) aCursorFrames
- (id) initWithFrames: (NSArray *) aCursorFrames type: (nsCursor) aType
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
@ -316,30 +323,31 @@ INIT_FAILURE:
NSEnumerator *it = [aCursorFrames objectEnumerator];
NSObject *frame = nil;
while ((frame = [it nextObject])) {
NS_ASSERTION([frame isKindOfClass: [NSCursor class]], "Invalid argument: All frames must be of type NSCursor");
NS_ASSERTION([frame isKindOfClass:[NSCursor class]], "Invalid argument: All frames must be of type NSCursor");
}
mFrames = [aCursorFrames retain];
mFrameCounter = 0;
mType = aType;
return self;
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
}
- (id) initWithCursor: (NSCursor *) aCursor
- (id) initWithCursor: (NSCursor *) aCursor type: (nsCursor) aType
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
NSArray *frame = [NSArray arrayWithObjects: aCursor, nil];
return [self initWithFrames: frame];
NSArray *frame = [NSArray arrayWithObjects:aCursor, nil];
return [self initWithFrames:frame type:aType];
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
}
- (id) initWithImageNamed: (NSString *) aCursorImage hotSpot: (NSPoint) aPoint
- (id) initWithImageNamed: (NSString *) aCursorImage hotSpot: (NSPoint) aPoint type: (nsCursor) aType
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
return [self initWithCursor: [nsMacCursor cocoaCursorWithImageNamed: aCursorImage hotSpot: aPoint]];
return [self initWithCursor:[nsMacCursor cocoaCursorWithImageNamed:aCursorImage hotSpot:aPoint] type:aType];
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
}
@ -353,7 +361,7 @@ INIT_FAILURE:
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
NSCursor* newCursor = [mFrames objectAtIndex: aFrameIndex];
NSCursor* newCursor = [mFrames objectAtIndex:aFrameIndex];
[newCursor set];
mLastSetCocoaCursor = newCursor;