Mac: Use cursor rects instead of NSCursor hide/unhide.
authorJørgen P. Tjernø <jorgen@valvesoftware.com>
Tue, 07 May 2013 16:52:39 -0700
changeset 7158 ff52fba70795
parent 7157 a082c2eeb247
child 7159 ffc613268eb1
Mac: Use cursor rects instead of NSCursor hide/unhide. This should hopefully fix a class of problems around cursor hiding not behaving correctly on Mac. http://bugzilla.libsdl.org/show_bug.cgi?id=1824
src/video/cocoa/SDL_cocoamouse.h
src/video/cocoa/SDL_cocoamouse.m
src/video/cocoa/SDL_cocoawindow.m
--- a/src/video/cocoa/SDL_cocoamouse.h	Mon May 06 23:02:37 2013 +0200
+++ b/src/video/cocoa/SDL_cocoamouse.h	Tue May 07 16:52:39 2013 -0700
@@ -35,6 +35,10 @@
     int deltaYOffset;
 } SDL_MouseData;
 
+@interface NSCursor (InvisibleCursor)
++ (NSCursor *)invisibleCursor;
+@end
+
 #endif /* _SDL_cocoamouse_h */
 
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/cocoa/SDL_cocoamouse.m	Mon May 06 23:02:37 2013 +0200
+++ b/src/video/cocoa/SDL_cocoamouse.m	Tue May 07 16:52:39 2013 -0700
@@ -28,6 +28,32 @@
 
 #include "../../events/SDL_mouse_c.h"
 
+@implementation NSCursor (InvisibleCursor)
++ (NSCursor *)invisibleCursor
+{
+    static NSCursor *invisibleCursor = NULL;
+    if (!invisibleCursor) {
+        /* RAW 16x16 transparent GIF */
+        static unsigned char cursorBytes[] = {
+            0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x10, 0x00, 0x10, 0x00, 0x80,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xF9, 0x04,
+            0x01, 0x00, 0x00, 0x01, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x10,
+            0x00, 0x10, 0x00, 0x00, 0x02, 0x0E, 0x8C, 0x8F, 0xA9, 0xCB, 0xED,
+            0x0F, 0xA3, 0x9C, 0xB4, 0xDA, 0x8B, 0xB3, 0x3E, 0x05, 0x00, 0x3B
+        };
+
+        NSData *cursorData = [NSData dataWithBytesNoCopy:&cursorBytes[0]
+                                                  length:sizeof(cursorBytes)
+                                            freeWhenDone:NO];
+        NSImage *cursorImage = [[[NSImage alloc] initWithData:cursorData] autorelease];
+        invisibleCursor = [[NSCursor alloc] initWithImage:cursorImage
+                                                  hotSpot:NSZeroPoint];
+    }
+
+    return invisibleCursor;
+}
+@end
+
 
 static SDL_Cursor *
 Cocoa_CreateDefaultCursor()
@@ -153,30 +179,17 @@
 static int
 Cocoa_ShowCursor(SDL_Cursor * cursor)
 {
-	/* We need to track the previous state because hide and unhide calls need to
-	 * be matched, but ShowCursor calls don't.
-	 */
-	static SDL_bool isShown = SDL_TRUE;
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 
-    if (cursor) {
-        NSCursor *nscursor = (NSCursor *)cursor->driverdata;
-
-        /* We're possibly executing from an event handler where this operation
-         * is unsupported. This will execute it in the main Cocoa event loop
-         * after this returns.
-         */
-        [nscursor performSelectorOnMainThread:@selector(set)
-                                   withObject:nil
-                                waitUntilDone:NO];
-
-		if (!isShown) {
-			[NSCursor unhide];
-			isShown = SDL_TRUE;
-		}
-	} else if (isShown) {
-		[NSCursor hide];
-		isShown = SDL_FALSE;
+    SDL_VideoDevice *device = SDL_GetVideoDevice();
+    SDL_Window *window = (device ? device->windows : NULL);
+    for (; window != NULL; window = window->next) {
+        SDL_WindowData *driverdata = (SDL_WindowData *)window->driverdata;
+        if (driverdata) {
+            [driverdata->nswindow performSelectorOnMainThread:@selector(invalidateCursorRectsForView:)
+                                                   withObject:[driverdata->nswindow contentView]
+                                                waitUntilDone:NO];
+        }
     }
 
     [pool release];
--- a/src/video/cocoa/SDL_cocoawindow.m	Mon May 06 23:02:37 2013 +0200
+++ b/src/video/cocoa/SDL_cocoawindow.m	Tue May 07 16:52:39 2013 -0700
@@ -254,7 +254,6 @@
 
         if (x >= 0 && x < window->w && y >= 0 && y < window->h) {
             SDL_SendMouseMotion(window, 0, 0, x, y);
-            SDL_SetCursor(NULL);
         }
     }
 
@@ -520,6 +519,7 @@
 @end
 
 @interface SDLView : NSView
+
 /* The default implementation doesn't pass rightMouseDown to responder chain */
 - (void)rightMouseDown:(NSEvent *)theEvent;
 @end
@@ -529,6 +529,20 @@
 {
     [[self nextResponder] rightMouseDown:theEvent];
 }
+
+- (void)resetCursorRects
+{
+    [super resetCursorRects];
+    SDL_Mouse *mouse = SDL_GetMouse();
+
+    if (mouse->cursor_shown && mouse->cur_cursor) {
+        [self addCursorRect:[self bounds]
+                     cursor:mouse->cur_cursor->driverdata];
+    } else {
+        [self addCursorRect:[self bounds]
+                     cursor:[NSCursor invisibleCursor]];
+    }
+}
 @end
 
 static unsigned int