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