Fix for bug #240
authorSam Lantinga <slouken@libsdl.org>
Sat, 24 Jun 2006 17:36:55 +0000
changeset 1883 2780f547f5e7
parent 1882 339d733e3699
child 1884 17af3557191c
Fix for bug #240 Christian Walther contributed Cocoa cursor code.
src/video/quartz/SDL_QuartzWM.m
test/testcursor.c
--- a/src/video/quartz/SDL_QuartzWM.m	Sat Jun 24 04:30:01 2006 +0000
+++ b/src/video/quartz/SDL_QuartzWM.m	Sat Jun 24 17:36:55 2006 +0000
@@ -25,49 +25,69 @@
 
 
 struct WMcursor {
-    Cursor curs;
+    NSCursor *nscursor;
 };
 
 void QZ_FreeWMCursor     (_THIS, WMcursor *cursor) { 
 
-    if ( cursor != NULL )
+    if ( cursor != NULL ) {
+        [ cursor->nscursor release ];
         free (cursor);
+    }
 }
 
-/* Use the Carbon cursor routines for now */
 WMcursor*    QZ_CreateWMCursor   (_THIS, Uint8 *data, Uint8 *mask, 
                                          int w, int h, int hot_x, int hot_y) { 
     WMcursor *cursor;
-    int row, bytes;
-        
+    NSBitmapImageRep *imgrep;
+    NSImage *img;
+    unsigned char *planes[5];
+    int i;
+    NSAutoreleasePool *pool;
+    
+    pool = [ [ NSAutoreleasePool alloc ] init ];
+    
     /* Allocate the cursor memory */
     cursor = (WMcursor *)SDL_malloc(sizeof(WMcursor));
-    if ( cursor == NULL ) {
-        SDL_OutOfMemory();
-        return(NULL);
-    }
-    SDL_memset(cursor, 0, sizeof(*cursor));
+    if (cursor == NULL) goto outOfMemory;
     
-    if (w > 16)
-        w = 16;
+    /* create the image representation and get the pointers to its storage */
+    imgrep = [ [ [ NSBitmapImageRep alloc ] initWithBitmapDataPlanes: NULL pixelsWide: w pixelsHigh: h bitsPerSample: 1 samplesPerPixel: 2 hasAlpha: YES isPlanar: YES colorSpaceName: NSDeviceBlackColorSpace bytesPerRow: (w+7)/8 bitsPerPixel: 0 ] autorelease ];
+    if (imgrep == nil) goto outOfMemory;
+    [ imgrep getBitmapDataPlanes: planes ];
     
-    if (h > 16)
-        h = 16;
+    /* copy data and mask, extending the mask to all black pixels because the inversion effect doesn't work with Cocoa's alpha-blended cursors */
+    for (i = 0; i < (w+7)/8*h; i++) {
+        planes[0][i] = data[i];
+        planes[1][i] = mask[i] | data[i];
+    }
     
-    bytes = (w+7)/8;
-
-    for ( row=0; row<h; ++row ) {
-        SDL_memcpy(&cursor->curs.data[row], data, bytes);
-        data += bytes;
+    /* create image and cursor */
+    img = [ [ [ NSImage alloc ] initWithSize: NSMakeSize(w, h) ] autorelease ];
+    if (img == nil) goto outOfMemory;
+    [ img addRepresentation: imgrep ];
+    if (system_version < 0x1030) { /* on 10.2, cursors must be 16*16 */
+        if (w > 16 || h > 16) { /* too big: scale it down */
+            [ img setScalesWhenResized: YES ];
+            hot_x = hot_x*16/w;
+            hot_y = hot_y*16/h;
+        }
+        else { /* too small (or just right): extend it (from the bottom left corner, so hot_y must be adjusted) */
+            hot_y += 16 - h;
+        }
+        [ img setSize: NSMakeSize(16, 16) ];
     }
-    for ( row=0; row<h; ++row ) {
-        SDL_memcpy(&cursor->curs.mask[row], mask, bytes);
-        mask += bytes;
-    }
-    cursor->curs.hotSpot.h = hot_x;
-    cursor->curs.hotSpot.v = hot_y;
+    cursor->nscursor = [ [ NSCursor alloc ] initWithImage: img hotSpot: NSMakePoint(hot_x, hot_y) ];
+    if (cursor->nscursor == nil) goto outOfMemory;
     
+    [ pool release ];
     return(cursor);
+
+outOfMemory:
+    [ pool release ];
+    if (cursor != NULL) SDL_free(cursor);
+    SDL_OutOfMemory();
+    return(NULL);
 }
 
 void QZ_ShowMouse (_THIS) {
@@ -103,7 +123,7 @@
         }
     }
     else {
-        SetCursor(&cursor->curs);
+        [ cursor->nscursor set ];
         if ( ! cursor_should_be_visible ) {
             QZ_ShowMouse (this);
             cursor_should_be_visible = YES;
--- a/test/testcursor.c	Sat Jun 24 04:30:01 2006 +0000
+++ b/test/testcursor.c	Sat Jun 24 17:36:55 2006 +0000
@@ -55,6 +55,10 @@
 	0xff00
 };
 
+/* another test cursor: smaller than 16x16, and with an odd height */
+
+Uint8 small_cursor_data[11] = { 0x00, 0x18, 0x08, 0x38, 0x44, 0x54, 0x44, 0x38, 0x20, 0x20, 0x00 };
+Uint8 small_cursor_mask[11] = { 0x3C, 0x3C, 0x3C, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x78, 0x70, 0x70 };
 
 /* XPM */
 static const char *arrow[] = {
@@ -139,7 +143,7 @@
 {
 	SDL_Surface *screen;
 	SDL_bool quit = SDL_FALSE, first_time = SDL_TRUE;
-	SDL_Cursor *cursor[2];
+	SDL_Cursor *cursor[3];
 	int current;
 
 	/* Load the SDL library */
@@ -170,6 +174,13 @@
 		SDL_Quit();
 		return(1);
 	}
+	cursor[2] = SDL_CreateCursor(small_cursor_data, small_cursor_mask,
+		8, 11, 3, 5);
+	if (cursor[2]==NULL) {
+		fprintf(stderr, "Couldn't initialize test cursor: %s\n",SDL_GetError());
+		SDL_Quit();
+		return(1);
+	}
 
 	current = 0;
 	SDL_SetCursor(cursor[current]);
@@ -179,7 +190,7 @@
 		while (SDL_PollEvent(&event)) {
 			switch(event.type) {
 				case SDL_MOUSEBUTTONDOWN:
-					current = !current;
+					current = (current + 1)%3;
 					SDL_SetCursor(cursor[current]);
 					break;
 				case SDL_KEYDOWN: