Back to index

lightning-sunbird  0.9+nobinonly
nsMacCursor.mm
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Camino Cursor code.
00015  *
00016  * The Initial Developer of the Original Code is 
00017  * Andrew Thompson.
00018  * Portions created by the Andrew Thompson are Copyright (C) 2004
00019  * Andrew Thompson. All Rights Reserved.
00020  * 
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #import "nsMacCursor.h"
00038 #import "nsMacResources.h"
00039 #import "nsDebug.h"
00040 
00046 @interface nsMacCursor (PrivateMethods)
00047 
00053 - (int) getNextCursorFrame;
00054 
00059 - (int) numFrames;
00060 
00066 - (void) createTimer;
00067 
00072 - (void) destroyTimer;
00084 - (void) spinCursor: (NSTimer *) aTimer;
00085 
00093 - (void) setFrame: (int) aFrameIndex;
00094 @end
00095 
00101 @interface nsThemeCursor : nsMacCursor
00102 {
00103   @private
00104   ThemeCursor mCursor;
00105 }
00106 
00113 - (id) initWithThemeCursor: (ThemeCursor) aCursor;
00114 @end
00115 
00122 @interface nsCocoaCursor : nsMacCursor
00123 {
00124   @private
00125   NSArray *mFrames;
00126 }
00127 
00136 - (id) initWithFrames: (NSArray *) aCursorFrames;
00137 
00144 - (id) initWithCursor: (NSCursor *) aCursor;
00145 
00156 - (id) initWithImageNamed: (NSString *) aCursorImage hotSpot: (NSPoint) aPoint;
00157 @end
00158 
00165 @interface nsResourceCursor : nsMacCursor
00166 {
00167   @private
00168   int mFirstFrame;
00169   int mLastFrame;
00170 }
00171 
00183 - (id) initWithFirstFrame: (int) aFirstFrame lastFrame: (int) aLastFrame;
00184 @end
00185 
00186 @implementation nsMacCursor
00187 
00188 + (nsMacCursor *) cursorWithThemeCursor: (ThemeCursor) aCursor
00189 {
00190   return [[[nsThemeCursor alloc] initWithThemeCursor: aCursor] autorelease];
00191 }
00192 
00193 + (nsMacCursor *) cursorWithResources: (int) aFirstFrame lastFrame: (int) aLastFrame
00194 {
00195   return [[[nsResourceCursor alloc] initWithFirstFrame: aFirstFrame lastFrame: aLastFrame] autorelease];
00196 }
00197 
00198 + (nsMacCursor *) cursorWithCursor: (NSCursor *) aCursor
00199 {
00200   return [[[nsCocoaCursor alloc] initWithCursor: aCursor] autorelease];
00201 }
00202 
00203 + (nsMacCursor *) cursorWithImageNamed: (NSString *) aCursorImage hotSpot: (NSPoint) aPoint
00204 {
00205   return [[[nsCocoaCursor alloc] initWithImageNamed: aCursorImage hotSpot: aPoint] autorelease];
00206 }
00207 
00208 + (nsMacCursor *) cursorWithFrames: (NSArray *) aCursorFrames
00209 {
00210   return [[[nsCocoaCursor alloc] initWithFrames: aCursorFrames] autorelease];
00211 }
00212 
00213 - (void) set
00214 {
00215   if ( [self isAnimated])
00216   {
00217     [self createTimer];
00218   }
00219   //if the cursor isn't animated or the timer creation fails for any reason...
00220   if (mTimer == nil)
00221   {
00222     [self setFrame: 0];
00223   }
00224 }
00225 
00226 - (void) unset
00227 {
00228   [self destroyTimer];    
00229 }
00230 
00231 - (BOOL) isAnimated
00232 {
00233   return [self numFrames] > 1;
00234 }
00235 
00236 - (int) numFrames
00237 {
00238   //subclasses need to override this to support animation
00239   return 1;
00240 }
00241 
00242 - (int) getNextCursorFrame
00243 {
00244   mFrameCounter = (mFrameCounter + 1) % [self numFrames];
00245   return mFrameCounter;
00246 }
00247 
00248 - (void) createTimer
00249 {
00250   if ( mTimer == nil)
00251   {
00252     mTimer = [[NSTimer scheduledTimerWithTimeInterval: 0.25
00253                                                target: self
00254                                              selector: @selector(spinCursor:)
00255                                              userInfo: nil
00256                                               repeats: YES] retain];
00257   }
00258 }
00259 
00260 - (void) destroyTimer
00261 {
00262   if ( mTimer != nil)
00263   {
00264       [mTimer invalidate];
00265       [mTimer release];
00266       mTimer = nil;
00267   }
00268 }
00269 
00270 - (void) spinCursor: (NSTimer *) aTimer
00271 {
00272   if ( [aTimer isValid] )
00273   {
00274     [self setFrame: [self getNextCursorFrame]];
00275   }
00276 }
00277 
00278 - (void) setFrame: (int) aFrameIndex
00279 {
00280   //subclasses need to do something useful here
00281 }
00282 
00283 - (void) dealloc
00284 {
00285   [self destroyTimer];
00286   [super dealloc];    
00287 }
00288 
00289 @end
00290 
00291 @implementation nsThemeCursor
00292 - (id) initWithThemeCursor: (ThemeCursor) aCursor
00293 {
00294   self = [super init];
00295   //Appearance Manager cursors all fall into the range 0..127. Custom application CURS resources begin at id 128.
00296   NS_ASSERTION(mCursor >= 0 && mCursor < 128, "Theme cursors must be in the range 0 <= num < 128");
00297   mCursor = aCursor;    
00298   return self;
00299 }
00300 
00301 - (void) setFrame: (int) aFrameIndex
00302 {
00303   if ( [self isAnimated] )
00304   {
00305     //if the cursor is animated try to draw the appropriate frame
00306     OSStatus err = ::SetAnimatedThemeCursor(mCursor, aFrameIndex);
00307     if ( err != noErr )
00308     {
00309       //in the event of any kind of problem, just try to show the first frame
00310       ::SetThemeCursor(mCursor);
00311     }
00312   }
00313   else
00314   {
00315     ::SetThemeCursor(mCursor);
00316   }
00317 }
00318 
00319 - (int) numFrames
00320 {
00321   //These don't appear to be documented. Trial and Error...
00322   switch (mCursor)
00323   {
00324     case kThemeWatchCursor:
00325     case kThemeSpinningCursor:            
00326       return 8;
00327     default:
00328       return 1;
00329   }
00330 }
00331 
00332 @end
00333 
00334 @implementation nsCocoaCursor
00335 - (id) initWithFrames: (NSArray *) aCursorFrames
00336 {
00337   self = [super init];
00338   NSEnumerator *it = [aCursorFrames objectEnumerator];
00339   NSObject *frame = nil;
00340   while ((frame = [it nextObject]) != nil)
00341   {
00342     NS_ASSERTION([frame isKindOfClass: [NSCursor class]], "Invalid argument: All frames must be of type NSCursor");
00343   }
00344   mFrames = [aCursorFrames retain];
00345   mFrameCounter = 0;
00346   return self;
00347 }
00348 
00349 - (id) initWithCursor: (NSCursor *) aCursor
00350 {
00351   NSArray *frame = [NSArray arrayWithObjects: aCursor, nil];
00352   return [self initWithFrames: frame];
00353 }
00354 
00355 - (id) initWithImageNamed: (NSString *) aCursorImage hotSpot: (NSPoint) aPoint
00356 {
00357   return [self initWithCursor: [[NSCursor alloc] initWithImage: [NSImage imageNamed: aCursorImage] hotSpot: aPoint]];
00358 }
00359 
00360 - (void) setFrame: (int) aFrameIndex
00361 {
00362   [[mFrames objectAtIndex: aFrameIndex] performSelectorOnMainThread: @selector(set)  withObject: nil waitUntilDone: NO];
00363 }
00364 
00365 - (int) numFrames
00366 {
00367   return [mFrames count];
00368 }
00369 
00370 - (NSString *) description
00371 {
00372   return [mFrames description];
00373 }
00374 
00375 - (void) dealloc
00376 {
00377   [mFrames release];
00378   [super dealloc];    
00379 }
00380 @end
00381 
00382 @implementation nsResourceCursor
00383 -(id) initWithFirstFrame: (int) aFirstFrame lastFrame: (int) aLastFrame
00384 {
00385   self= [super init];
00386   //Appearance Manager cursors all fall into the range 0..127. Custom application CURS resources begin at id 128.
00387   NS_ASSERTION(aFirstFrame >= 128 && aLastFrame >= 128 && aLastFrame >= aFirstFrame, "Nonsensical frame indicies");
00388   mFirstFrame = aFirstFrame;
00389   mLastFrame = aLastFrame;
00390   return self;
00391 }
00392 
00393 - (void) setFrame: (int) aFrameIndex
00394 {
00395   nsMacResources::OpenLocalResourceFile();
00396   CursHandle cursHandle = ::GetCursor(mFirstFrame + aFrameIndex);
00397   NS_ASSERTION(cursHandle, "Can't load cursor, is the resource file installed correctly?");
00398   if (cursHandle)
00399   {
00400     ::SetCursor(*cursHandle);
00401   }
00402   nsMacResources::CloseLocalResourceFile();
00403 }
00404 
00405 - (int) numFrames
00406 {
00407   return (mLastFrame - mFirstFrame) + 1;
00408 }
00409 @end