From b8c18f61647d44ecaab2422e42b5d022830b4728 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sat, 24 Jun 2006 17:36:55 +0000 Subject: [PATCH] Fix for bug #240 Christian Walther contributed Cocoa cursor code. --- src/video/quartz/SDL_QuartzWM.m | 72 +++++++++++++++++++++------------ test/testcursor.c | 15 ++++++- 2 files changed, 59 insertions(+), 28 deletions(-) diff --git a/src/video/quartz/SDL_QuartzWM.m b/src/video/quartz/SDL_QuartzWM.m index 10f260cdb..dab99f6c1 100644 --- a/src/video/quartz/SDL_QuartzWM.m +++ b/src/video/quartz/SDL_QuartzWM.m @@ -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; - - bytes = (w+7)/8; - - for ( row=0; rowcurs.data[row], data, bytes); - data += bytes; + /* 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]; } - for ( row=0; rowcurs.mask[row], mask, bytes); - mask += 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) ]; } - 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 @@ int QZ_ShowWMCursor (_THIS, WMcursor *cursor) { } } else { - SetCursor(&cursor->curs); + [ cursor->nscursor set ]; if ( ! cursor_should_be_visible ) { QZ_ShowMouse (this); cursor_should_be_visible = YES; diff --git a/test/testcursor.c b/test/testcursor.c index 715beae3f..863b83941 100644 --- a/test/testcursor.c +++ b/test/testcursor.c @@ -55,6 +55,10 @@ Uint16 cursor_mask[16]={ 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 @@ int main(int argc, char *argv[]) { 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 @@ int main(int argc, char *argv[]) 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 @@ int main(int argc, char *argv[]) while (SDL_PollEvent(&event)) { switch(event.type) { case SDL_MOUSEBUTTONDOWN: - current = !current; + current = (current + 1)%3; SDL_SetCursor(cursor[current]); break; case SDL_KEYDOWN: