diff --git a/src/video/cocoa/SDL_cocoamouse.m b/src/video/cocoa/SDL_cocoamouse.m index 25041eb64..f6534b334 100644 --- a/src/video/cocoa/SDL_cocoamouse.m +++ b/src/video/cocoa/SDL_cocoamouse.m @@ -105,6 +105,45 @@ Cocoa_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y) return cursor; }} +/* there are .pdf files of some of the cursors we need, installed by default on macOS, but not available through NSCursor. + If we can load them ourselves, use them, otherwise fallback to something standard but not super-great. + Since these are under /System, they should be available even to sandboxed apps. */ +static NSCursor * +LoadHiddenSystemCursor(NSString *cursorName, SEL fallback) +{ + NSString *cursorPath = [@"/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/HIServices.framework/Versions/A/Resources/cursors" stringByAppendingPathComponent:cursorName]; + NSImage *image = [[NSImage alloc] initWithContentsOfFile:[cursorPath stringByAppendingPathComponent:@"cursor.pdf"]]; + if ((image == nil) || (image.valid == NO)) { + return [NSCursor performSelector:fallback]; + } + + NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[cursorPath stringByAppendingPathComponent:@"info.plist"]]; + + /* we can't do animation atm. :/ */ + const int frames = [[info valueForKey:@"frames"] integerValue]; + if (frames > 1) { + const NSSize cropped_size = NSMakeSize(image.size.width, (int) (image.size.height / frames)); + NSImage *cropped = [[NSImage alloc] initWithSize:cropped_size]; + if (cropped == nil) { + return [NSCursor performSelector:fallback]; + } + + #ifdef MAC_OS_VERSION_12_0 /* same value as deprecated symbol. */ + const NSCompositingOperation operation = NSCompositingOperationCopy; + #else + const NSCompositingOperation operation = NSCompositeCopy; + #endif + [cropped lockFocus]; + const NSRect cropped_rect = NSMakeRect(0, 0, cropped_size.width, cropped_size.height); + [image drawInRect:cropped_rect fromRect:cropped_rect operation:operation fraction:1]; + [cropped unlockFocus]; + image = cropped; + } + + NSCursor *cursor = [[NSCursor alloc] initWithImage:image hotSpot:NSMakePoint([[info valueForKey:@"hotx"] doubleValue], [[info valueForKey:@"hoty"] doubleValue])]; + return cursor; +} + static SDL_Cursor * Cocoa_CreateSystemCursor(SDL_SystemCursor id) { @autoreleasepool @@ -119,27 +158,29 @@ Cocoa_CreateSystemCursor(SDL_SystemCursor id) case SDL_SYSTEM_CURSOR_IBEAM: nscursor = [NSCursor IBeamCursor]; break; - case SDL_SYSTEM_CURSOR_WAIT: - nscursor = [NSCursor arrowCursor]; - break; case SDL_SYSTEM_CURSOR_CROSSHAIR: nscursor = [NSCursor crosshairCursor]; break; - case SDL_SYSTEM_CURSOR_WAITARROW: - nscursor = [NSCursor arrowCursor]; + case SDL_SYSTEM_CURSOR_WAIT: /* !!! FIXME: this is more like WAITARROW */ + nscursor = LoadHiddenSystemCursor(@"busybutclickable", @selector(arrowCursor)); + break; + case SDL_SYSTEM_CURSOR_WAITARROW: /* !!! FIXME: this is meant to be animated */ + nscursor = LoadHiddenSystemCursor(@"busybutclickable", @selector(arrowCursor)); break; case SDL_SYSTEM_CURSOR_SIZENWSE: + nscursor = LoadHiddenSystemCursor(@"resizenorthwestsoutheast", @selector(closedHandCursor)); + break; case SDL_SYSTEM_CURSOR_SIZENESW: - nscursor = [NSCursor closedHandCursor]; + nscursor = LoadHiddenSystemCursor(@"resizenortheastsouthwest", @selector(closedHandCursor)); break; case SDL_SYSTEM_CURSOR_SIZEWE: - nscursor = [NSCursor resizeLeftRightCursor]; + nscursor = LoadHiddenSystemCursor(@"resizeeastwest", @selector(resizeLeftRightCursor)); break; case SDL_SYSTEM_CURSOR_SIZENS: - nscursor = [NSCursor resizeUpDownCursor]; + nscursor = LoadHiddenSystemCursor(@"resizenorthsouth", @selector(resizeUpDownCursor)); break; case SDL_SYSTEM_CURSOR_SIZEALL: - nscursor = [NSCursor closedHandCursor]; + nscursor = LoadHiddenSystemCursor(@"move", @selector(closedHandCursor)); break; case SDL_SYSTEM_CURSOR_NO: nscursor = [NSCursor operationNotAllowedCursor];