1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is Camino Cursor code.
16 * The Initial Developer of the Original Code is
18 * Portions created by the Andrew Thompson are Copyright (C) 2004
19 * Andrew Thompson. All Rights Reserved.
22 * Josh Aas <josh@mozilla.com>
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #include "nsMacCursor.h"
39 #include "nsObjCExceptions.h"
41 #include "nsDirectoryServiceDefs.h"
46 /*! @category nsMacCursor (PrivateMethods)
47 @abstract Private methods internal to the nsMacCursor class.
48 @discussion <code>nsMacCursor</code> is effectively an abstract class. It does not define complete
49 behaviour in and of itself, the subclasses defined in this file provide the useful implementations.
51 @interface nsMacCursor (PrivateMethods)
53 /*! @method getNextCursorFrame
54 @abstract get the index of the next cursor frame to display.
55 @discussion Increments and returns the frame counter of an animated cursor.
56 @result The index of the next frame to display in the cursor animation
58 - (int) getNextCursorFrame;
61 @abstract Query the number of frames in this cursor's animation.
62 @discussion Returns the number of frames in this cursor's animation. Static cursors return 1.
66 /*! @method createTimer
67 @abstract Create a Timer to use to animate the cursor.
68 @discussion Creates an instance of <code>NSTimer</code> which is used to drive the cursor animation.
69 This method should only be called for cursors that are animated.
73 /*! @method destroyTimer
74 @abstract Destroy any timer instance associated with this cursor.
75 @discussion Invalidates and releases any <code>NSTimer</code> instance associated with this cursor.
77 - (void) destroyTimer;
78 /*! @method destroyTimer
79 @abstract Destroy any timer instance associated with this cursor.
80 @discussion Invalidates and releases any <code>NSTimer</code> instance associated with this cursor.
83 /*! @method advanceAnimatedCursor:
84 @abstract Method called by animation timer to perform animation.
85 @discussion Called by an animated cursor's associated timer to advance the animation to the next frame.
86 Determines which frame should occur next and sets the cursor to that frame.
87 @param aTimer the timer causing the animation
89 - (void) advanceAnimatedCursor: (NSTimer *) aTimer;
92 @abstract Sets the current cursor, using an index to determine which frame in the animation to display.
93 @discussion Sets the current cursor. The frame index determines which frame is shown if the cursor is animated.
94 Frames and numbered from <code>0</code> to <code>-[nsMacCursor numFrames] - 1</code>. A static cursor
95 has a single frame, numbered 0.
96 @param aFrameIndex the index indicating which frame from the animation to display
98 - (void) setFrame: (int) aFrameIndex;
102 /*! @class nsCocoaCursor
103 @abstract Implementation of <code>nsMacCursor</code> that uses Cocoa <code>NSCursor</code> instances.
104 @discussion Displays a static or animated cursor, using Cocoa <code>NSCursor</code> instances. These can be either
105 built-in <code>NSCursor</code> instances, or custom <code>NSCursor</code>s created from images.
106 When more than one <code>NSCursor</code> is provided, the cursor will use these as animation frames.
108 @interface nsCocoaCursor : nsMacCursor
112 NSCursor *mLastSetCocoaCursor;
115 /*! @method initWithFrames:
116 @abstract Create an animated cursor by specifying the frames to use for the animation.
117 @discussion Creates a cursor that will animate by cycling through the given frames. Each element of the array
118 must be an instance of <code>NSCursor</code>
119 @param aCursorFrames an array of <code>NSCursor</code>, representing the frames of an animated cursor, in the
120 order they should be played.
121 @param aType the corresponding <code>nsCursor</code> constant
122 @result an instance of <code>nsCocoaCursor</code> that will animate the given cursor frames
124 - (id) initWithFrames: (NSArray *) aCursorFrames type: (nsCursor) aType;
126 /*! @method initWithCursor:
127 @abstract Create a cursor by specifying a Cocoa <code>NSCursor</code>.
128 @discussion Creates a cursor representing the given Cocoa built-in cursor.
129 @param aCursor the <code>NSCursor</code> to use
130 @param aType the corresponding <code>nsCursor</code> constant
131 @result an instance of <code>nsCocoaCursor</code> representing the given <code>NSCursor</code>
133 - (id) initWithCursor: (NSCursor *) aCursor type: (nsCursor) aType;
135 /*! @method initWithImageNamed:hotSpot:
136 @abstract Create a cursor by specifying the name of an image resource to use for the cursor and a hotspot.
137 @discussion Creates a cursor by loading the named image using the <code>+[NSImage imageNamed:]</code> method.
138 <p>The image must be compatible with any restrictions laid down by <code>NSCursor</code>. These vary
139 by operating system version.</p>
140 <p>The hotspot precisely determines the point where the user clicks when using the cursor.</p>
141 @param aCursor the name of the image to use for the cursor
142 @param aPoint the point within the cursor to use as the hotspot
143 @param aType the corresponding <code>nsCursor</code> constant
144 @result an instance of <code>nsCocoaCursor</code> that uses the given image and hotspot
146 - (id) initWithImageNamed: (NSString *) aCursorImage hotSpot: (NSPoint) aPoint type: (nsCursor) aType;
150 @implementation nsMacCursor
152 + (nsMacCursor *) cursorWithCursor: (NSCursor *) aCursor type: (nsCursor) aType
154 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
156 return [[[nsCocoaCursor alloc] initWithCursor:aCursor type:aType] autorelease];
158 NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
161 + (nsMacCursor *) cursorWithImageNamed: (NSString *) aCursorImage hotSpot: (NSPoint) aPoint type: (nsCursor) aType
163 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
165 return [[[nsCocoaCursor alloc] initWithImageNamed:aCursorImage hotSpot:aPoint type:aType] autorelease];
167 NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
170 + (nsMacCursor *) cursorWithFrames: (NSArray *) aCursorFrames type: (nsCursor) aType
172 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
174 return [[[nsCocoaCursor alloc] initWithFrames:aCursorFrames type:aType] autorelease];
176 NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
179 + (NSCursor *) cocoaCursorWithImageNamed: (NSString *) imageName hotSpot: (NSPoint) aPoint
181 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
183 nsCOMPtr<nsIFile> resDir;
184 nsCAutoString resPath;
185 NSString* pathToImage;
186 NSImage* cursorImage;
188 nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(resDir));
191 resDir->AppendNative(NS_LITERAL_CSTRING("res"));
192 resDir->AppendNative(NS_LITERAL_CSTRING("cursors"));
194 rv = resDir->GetNativePath(resPath);
198 pathToImage = [NSString stringWithUTF8String:(const char*)resPath.get()];
201 pathToImage = [pathToImage stringByAppendingPathComponent:imageName];
202 pathToImage = [pathToImage stringByAppendingPathExtension:@"tiff"];
204 cursorImage = [[[NSImage alloc] initWithContentsOfFile:pathToImage] autorelease];
207 return [[[NSCursor alloc] initWithImage:cursorImage hotSpot:aPoint] autorelease];
210 NS_WARNING("Problem getting path to cursor image file!");
214 NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
219 // implemented by subclasses
225 if ([self isAnimated]) {
228 // if the cursor isn't animated or the timer creation fails for any reason...
241 return [self numFrames] > 1;
246 // subclasses need to override this to support animation
250 - (int) getNextCursorFrame
252 mFrameCounter = (mFrameCounter + 1) % [self numFrames];
253 return mFrameCounter;
258 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
261 mTimer = [[NSTimer scheduledTimerWithTimeInterval:0.25
263 selector:@selector(advanceAnimatedCursor:)
265 repeats:YES] retain];
268 NS_OBJC_END_TRY_ABORT_BLOCK;
271 - (void) destroyTimer
273 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
281 NS_OBJC_END_TRY_ABORT_BLOCK;
284 - (void) advanceAnimatedCursor: (NSTimer *) aTimer
286 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
288 if ([aTimer isValid]) {
289 [self setFrame:[self getNextCursorFrame]];
292 NS_OBJC_END_TRY_ABORT_BLOCK;
295 - (void) setFrame: (int) aFrameIndex
297 // subclasses need to do something useful here
306 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
311 NS_OBJC_END_TRY_ABORT_BLOCK;
316 @implementation nsCocoaCursor
318 - (id) initWithFrames: (NSArray *) aCursorFrames type: (nsCursor) aType
320 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
323 NSEnumerator *it = [aCursorFrames objectEnumerator];
324 NSObject *frame = nil;
325 while ((frame = [it nextObject])) {
326 NS_ASSERTION([frame isKindOfClass:[NSCursor class]], "Invalid argument: All frames must be of type NSCursor");
328 mFrames = [aCursorFrames retain];
333 NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
336 - (id) initWithCursor: (NSCursor *) aCursor type: (nsCursor) aType
338 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
340 NSArray *frame = [NSArray arrayWithObjects:aCursor, nil];
341 return [self initWithFrames:frame type:aType];
343 NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
346 - (id) initWithImageNamed: (NSString *) aCursorImage hotSpot: (NSPoint) aPoint type: (nsCursor) aType
348 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
350 return [self initWithCursor:[nsMacCursor cocoaCursorWithImageNamed:aCursorImage hotSpot:aPoint] type:aType];
352 NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
357 return [NSCursor currentCursor] == mLastSetCocoaCursor;
360 - (void) setFrame: (int) aFrameIndex
362 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
364 NSCursor* newCursor = [mFrames objectAtIndex:aFrameIndex];
366 mLastSetCocoaCursor = newCursor;
368 NS_OBJC_END_TRY_ABORT_BLOCK;
373 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
375 return [mFrames count];
377 NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0);
380 - (NSString *) description
382 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
384 return [mFrames description];
386 NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
391 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
396 NS_OBJC_END_TRY_ABORT_BLOCK;