widget/cocoa/nsCursorManager.mm

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/widget/cocoa/nsCursorManager.mm	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,308 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +#include "imgIContainer.h"
     1.9 +#include "nsCocoaUtils.h"
    1.10 +#include "nsCursorManager.h"
    1.11 +#include "nsObjCExceptions.h"
    1.12 +#include <math.h>
    1.13 +
    1.14 +static nsCursorManager *gInstance;
    1.15 +static CGFloat sCursorScaleFactor = 0.0f;
    1.16 +static imgIContainer *sCursorImgContainer = nullptr;
    1.17 +static const nsCursor sCustomCursor = eCursorCount;
    1.18 +
    1.19 +/*! @category nsCursorManager(PrivateMethods)
    1.20 +    Private methods for the cursor manager class.
    1.21 +*/
    1.22 +@interface nsCursorManager(PrivateMethods)
    1.23 +/*! @method     getCursor:
    1.24 +    @abstract   Get a reference to the native Mac representation of a cursor.
    1.25 +    @discussion Gets a reference to the Mac native implementation of a cursor.
    1.26 +                If the cursor has been requested before, it is retreived from the cursor cache,
    1.27 +                otherwise it is created and cached.
    1.28 +    @param      aCursor the cursor to get
    1.29 +    @result     the Mac native implementation of the cursor
    1.30 +*/
    1.31 +- (nsMacCursor *) getCursor: (nsCursor) aCursor;
    1.32 +
    1.33 +/*! @method     setMacCursor:
    1.34 + @abstract   Set the current Mac native cursor
    1.35 + @discussion Sets the current cursor - this routine is what actually causes the cursor to change.
    1.36 + The argument is retained and the old cursor is released.
    1.37 + @param      aMacCursor the cursor to set
    1.38 + @result     NS_OK
    1.39 + */
    1.40 +- (nsresult) setMacCursor: (nsMacCursor*) aMacCursor;
    1.41 +
    1.42 +/*! @method     createCursor:
    1.43 +    @abstract   Create a Mac native representation of a cursor.
    1.44 +    @discussion Creates a version of the Mac native representation of this cursor
    1.45 +    @param      aCursor the cursor to create
    1.46 +    @result     the Mac native implementation of the cursor
    1.47 +*/
    1.48 ++ (nsMacCursor *) createCursor: (enum nsCursor) aCursor;
    1.49 +
    1.50 +@end
    1.51 +
    1.52 +@implementation nsCursorManager
    1.53 +
    1.54 ++ (nsCursorManager *) sharedInstance
    1.55 +{
    1.56 +  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
    1.57 +
    1.58 +  if (!gInstance) {
    1.59 +    gInstance = [[nsCursorManager alloc] init];
    1.60 +  }
    1.61 +  return gInstance;
    1.62 +
    1.63 +  NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
    1.64 +}
    1.65 +
    1.66 ++ (void) dispose
    1.67 +{
    1.68 +  NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
    1.69 +
    1.70 +  [gInstance release];
    1.71 +  gInstance = nil;
    1.72 +
    1.73 +  NS_OBJC_END_TRY_ABORT_BLOCK;
    1.74 +}
    1.75 +
    1.76 ++ (nsMacCursor *) createCursor: (enum nsCursor) aCursor
    1.77 +{
    1.78 +  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
    1.79 +
    1.80 +  switch(aCursor)
    1.81 +  {
    1.82 +    SEL cursorSelector;
    1.83 +    case eCursor_standard:
    1.84 +      return [nsMacCursor cursorWithCursor:[NSCursor arrowCursor] type:aCursor];
    1.85 +    case eCursor_wait:
    1.86 +    case eCursor_spinning:
    1.87 +    {
    1.88 +      return [nsMacCursor cursorWithCursor:[NSCursor busyButClickableCursor] type:aCursor];
    1.89 +    }
    1.90 +    case eCursor_select:
    1.91 +      return [nsMacCursor cursorWithCursor:[NSCursor IBeamCursor] type:aCursor];
    1.92 +    case eCursor_hyperlink:
    1.93 +      return [nsMacCursor cursorWithCursor:[NSCursor pointingHandCursor] type:aCursor];
    1.94 +    case eCursor_crosshair:
    1.95 +      return [nsMacCursor cursorWithCursor:[NSCursor crosshairCursor] type:aCursor];
    1.96 +    case eCursor_move:
    1.97 +      return [nsMacCursor cursorWithImageNamed:@"move" hotSpot:NSMakePoint(12,12) type:aCursor];
    1.98 +    case eCursor_help:
    1.99 +      return [nsMacCursor cursorWithImageNamed:@"help" hotSpot:NSMakePoint(12,12) type:aCursor];
   1.100 +    case eCursor_copy:
   1.101 +      cursorSelector = @selector(dragCopyCursor);
   1.102 +      return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector] ?
   1.103 +              [NSCursor performSelector:cursorSelector] :
   1.104 +              [NSCursor arrowCursor] type:aCursor];
   1.105 +    case eCursor_alias:
   1.106 +      cursorSelector = @selector(dragLinkCursor);
   1.107 +      return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector] ?
   1.108 +              [NSCursor performSelector:cursorSelector] :
   1.109 +              [NSCursor arrowCursor] type:aCursor];
   1.110 +    case eCursor_context_menu:
   1.111 +      cursorSelector = @selector(contextualMenuCursor);
   1.112 +      return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector] ?
   1.113 +              [NSCursor performSelector:cursorSelector] :
   1.114 +              [NSCursor arrowCursor] type:aCursor];
   1.115 +    case eCursor_cell:
   1.116 +      return [nsMacCursor cursorWithImageNamed:@"cell" hotSpot:NSMakePoint(12,12) type:aCursor];
   1.117 +    case eCursor_grab:
   1.118 +      return [nsMacCursor cursorWithCursor:[NSCursor openHandCursor] type:aCursor];
   1.119 +    case eCursor_grabbing:
   1.120 +      return [nsMacCursor cursorWithCursor:[NSCursor closedHandCursor] type:aCursor];
   1.121 +    case eCursor_zoom_in:
   1.122 +      return [nsMacCursor cursorWithImageNamed:@"zoomIn" hotSpot:NSMakePoint(10,10) type:aCursor];
   1.123 +    case eCursor_zoom_out:
   1.124 +      return [nsMacCursor cursorWithImageNamed:@"zoomOut" hotSpot:NSMakePoint(10,10) type:aCursor];
   1.125 +    case eCursor_vertical_text:
   1.126 +      return [nsMacCursor cursorWithImageNamed:@"vtIBeam" hotSpot:NSMakePoint(12,11) type:aCursor];
   1.127 +    case eCursor_all_scroll:
   1.128 +      return [nsMacCursor cursorWithCursor:[NSCursor openHandCursor] type:aCursor];
   1.129 +    case eCursor_not_allowed:
   1.130 +    case eCursor_no_drop:
   1.131 +      cursorSelector = @selector(operationNotAllowedCursor);
   1.132 +      return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector] ?
   1.133 +              [NSCursor performSelector:cursorSelector] :
   1.134 +              [NSCursor arrowCursor] type:aCursor];
   1.135 +    // Resize Cursors:
   1.136 +    // North
   1.137 +    case eCursor_n_resize:
   1.138 +        return [nsMacCursor cursorWithCursor:[NSCursor resizeUpCursor] type:aCursor];
   1.139 +    // North East
   1.140 +    case eCursor_ne_resize:
   1.141 +        return [nsMacCursor cursorWithImageNamed:@"sizeNE" hotSpot:NSMakePoint(12,11) type:aCursor];
   1.142 +    // East
   1.143 +    case eCursor_e_resize:
   1.144 +        return [nsMacCursor cursorWithCursor:[NSCursor resizeRightCursor] type:aCursor];
   1.145 +    // South East
   1.146 +    case eCursor_se_resize:
   1.147 +        return [nsMacCursor cursorWithImageNamed:@"sizeSE" hotSpot:NSMakePoint(12,12) type:aCursor];
   1.148 +    // South
   1.149 +    case eCursor_s_resize:
   1.150 +        return [nsMacCursor cursorWithCursor:[NSCursor resizeDownCursor] type:aCursor];
   1.151 +    // South West
   1.152 +    case eCursor_sw_resize:
   1.153 +        return [nsMacCursor cursorWithImageNamed:@"sizeSW" hotSpot:NSMakePoint(10,12) type:aCursor];
   1.154 +    // West
   1.155 +    case eCursor_w_resize:
   1.156 +        return [nsMacCursor cursorWithCursor:[NSCursor resizeLeftCursor] type:aCursor];
   1.157 +    // North West
   1.158 +    case eCursor_nw_resize:
   1.159 +        return [nsMacCursor cursorWithImageNamed:@"sizeNW" hotSpot:NSMakePoint(11,11) type:aCursor];
   1.160 +    // North & South
   1.161 +    case eCursor_ns_resize:
   1.162 +        return [nsMacCursor cursorWithCursor:[NSCursor resizeUpDownCursor] type:aCursor];
   1.163 +    // East & West
   1.164 +    case eCursor_ew_resize:
   1.165 +        return [nsMacCursor cursorWithCursor:[NSCursor resizeLeftRightCursor] type:aCursor];
   1.166 +    // North East & South West
   1.167 +    case eCursor_nesw_resize:
   1.168 +        return [nsMacCursor cursorWithImageNamed:@"sizeNESW" hotSpot:NSMakePoint(12,12) type:aCursor];
   1.169 +    // North West & South East
   1.170 +    case eCursor_nwse_resize:
   1.171 +        return [nsMacCursor cursorWithImageNamed:@"sizeNWSE" hotSpot:NSMakePoint(12,12) type:aCursor];
   1.172 +    // Column Resize
   1.173 +    case eCursor_col_resize:
   1.174 +        return [nsMacCursor cursorWithImageNamed:@"colResize" hotSpot:NSMakePoint(12,12) type:aCursor];
   1.175 +    // Row Resize
   1.176 +    case eCursor_row_resize:
   1.177 +        return [nsMacCursor cursorWithImageNamed:@"rowResize" hotSpot:NSMakePoint(12,12) type:aCursor];
   1.178 +    default:
   1.179 +        return [nsMacCursor cursorWithCursor:[NSCursor arrowCursor] type:aCursor];
   1.180 +  }
   1.181 +
   1.182 +  NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
   1.183 +}
   1.184 +
   1.185 +- (id) init
   1.186 +{
   1.187 +  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
   1.188 +
   1.189 +  if ((self = [super init])) {
   1.190 +    mCursors = [[NSMutableDictionary alloc] initWithCapacity:25];
   1.191 +  }
   1.192 +  return self;
   1.193 +
   1.194 +  NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
   1.195 +}
   1.196 +
   1.197 +- (nsresult) setCursor: (enum nsCursor) aCursor
   1.198 +{
   1.199 +  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
   1.200 +
   1.201 +  // Some plugins mess with our cursors and set a cursor that even
   1.202 +  // [NSCursor currentCursor] doesn't know about. In case that happens, just
   1.203 +  // reset the state.
   1.204 +  [[NSCursor currentCursor] set];
   1.205 +
   1.206 +  nsCursor oldType = [mCurrentMacCursor type];
   1.207 +  if (oldType != aCursor) {
   1.208 +    if (aCursor == eCursor_none) {
   1.209 +      [NSCursor hide];
   1.210 +    } else if (oldType == eCursor_none) {
   1.211 +      [NSCursor unhide];
   1.212 +    }
   1.213 +  }
   1.214 +  [self setMacCursor:[self getCursor:aCursor]];
   1.215 +
   1.216 +  // if a custom cursor was previously set, release sCursorImgContainer
   1.217 +  if (oldType == sCustomCursor) {
   1.218 +    NS_IF_RELEASE(sCursorImgContainer);
   1.219 +  }
   1.220 +  return NS_OK;
   1.221 +  
   1.222 +  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
   1.223 +}
   1.224 +
   1.225 +- (nsresult) setMacCursor: (nsMacCursor*) aMacCursor
   1.226 +{
   1.227 +  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
   1.228 +
   1.229 +  if (mCurrentMacCursor != aMacCursor || ![mCurrentMacCursor isSet]) {
   1.230 +    [aMacCursor retain];
   1.231 +    [mCurrentMacCursor unset];
   1.232 +    [aMacCursor set];
   1.233 +    [mCurrentMacCursor release];
   1.234 +    mCurrentMacCursor = aMacCursor;
   1.235 +  }
   1.236 +
   1.237 +  return NS_OK;
   1.238 +  
   1.239 +  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
   1.240 +}
   1.241 +
   1.242 +- (nsresult) setCursorWithImage: (imgIContainer*) aCursorImage hotSpotX: (uint32_t) aHotspotX hotSpotY: (uint32_t) aHotspotY scaleFactor: (CGFloat) scaleFactor
   1.243 +{
   1.244 +  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
   1.245 +  // As the user moves the mouse, this gets called repeatedly with the same aCursorImage
   1.246 +  if (sCursorImgContainer == aCursorImage && sCursorScaleFactor == scaleFactor && mCurrentMacCursor) {
   1.247 +    [self setMacCursor:mCurrentMacCursor];
   1.248 +    return NS_OK;
   1.249 +  }
   1.250 +  
   1.251 +  [[NSCursor currentCursor] set];
   1.252 +  int32_t width = 0, height = 0;
   1.253 +  aCursorImage->GetWidth(&width);
   1.254 +  aCursorImage->GetHeight(&height);
   1.255 +  // prevent DoS attacks
   1.256 +  if (width > 128 || height > 128) {
   1.257 +    return NS_OK;
   1.258 +  }
   1.259 +
   1.260 +  NSImage *cursorImage;
   1.261 +  nsresult rv = nsCocoaUtils::CreateNSImageFromImageContainer(aCursorImage, imgIContainer::FRAME_FIRST, &cursorImage, scaleFactor);
   1.262 +  if (NS_FAILED(rv) || !cursorImage) {
   1.263 +    return NS_ERROR_FAILURE;
   1.264 +  }
   1.265 +
   1.266 +  // if the hotspot is nonsensical, make it 0,0
   1.267 +  aHotspotX = (aHotspotX > (uint32_t)width - 1) ? 0 : aHotspotX;
   1.268 +  aHotspotY = (aHotspotY > (uint32_t)height - 1) ? 0 : aHotspotY;
   1.269 +
   1.270 +  NSPoint hotSpot = ::NSMakePoint(aHotspotX, aHotspotY);
   1.271 +  [self setMacCursor:[nsMacCursor cursorWithCursor:[[NSCursor alloc] initWithImage:cursorImage hotSpot:hotSpot] type:sCustomCursor]];
   1.272 +  [cursorImage release];
   1.273 +  
   1.274 +  NS_IF_RELEASE(sCursorImgContainer);
   1.275 +  sCursorImgContainer = aCursorImage;
   1.276 +  sCursorScaleFactor = scaleFactor;
   1.277 +  NS_ADDREF(sCursorImgContainer);
   1.278 +  
   1.279 +  return NS_OK;
   1.280 +  
   1.281 +  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
   1.282 +}
   1.283 +
   1.284 +- (nsMacCursor *) getCursor: (enum nsCursor) aCursor
   1.285 +{
   1.286 +  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
   1.287 +
   1.288 +  nsMacCursor * result = [mCursors objectForKey:[NSNumber numberWithInt:aCursor]];
   1.289 +  if (!result) {
   1.290 +    result = [nsCursorManager createCursor:aCursor];
   1.291 +    [mCursors setObject:result forKey:[NSNumber numberWithInt:aCursor]];
   1.292 +  }
   1.293 +  return result;
   1.294 +
   1.295 +  NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
   1.296 +}
   1.297 +
   1.298 +- (void) dealloc
   1.299 +{
   1.300 +  NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
   1.301 +
   1.302 +  [mCurrentMacCursor unset];
   1.303 +  [mCurrentMacCursor release];
   1.304 +  [mCursors release];
   1.305 +  NS_IF_RELEASE(sCursorImgContainer);
   1.306 +  [super dealloc];
   1.307 +
   1.308 +  NS_OBJC_END_TRY_ABORT_BLOCK;
   1.309 +}
   1.310 +
   1.311 +@end

mercurial