src/video/quartz/SDL_QuartzWM.m
author Sam Lantinga <slouken@libsdl.org>
Fri, 18 Jan 2002 19:41:59 +0000
changeset 269 4125b9859c71
parent 252 e8157fcb3114
child 272 d1447a846d80
permissions -rw-r--r--
Added Quartz version of SDL_SetIcon() for MacOS X (thanks Bob)

/*
    SDL - Simple DirectMedia Layer
    Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Sam Lantinga
    slouken@libsdl.org
*/

struct WMcursor {
    Cursor curs;
};

static void QZ_FreeWMCursor     (_THIS, WMcursor *cursor) { 

    if ( cursor != NULL )
        free (cursor);
}

/* Use the Carbon cursor routines for now */
static WMcursor*    QZ_CreateWMCursor   (_THIS, Uint8 *data, Uint8 *mask, 
                                          int w, int h, int hot_x, int hot_y) { 
	WMcursor *cursor;
	int row, bytes;
		
	/* Allocate the cursor memory */
	cursor = (WMcursor *)malloc(sizeof(WMcursor));
	if ( cursor == NULL ) {
		SDL_OutOfMemory();
		return(NULL);
	}
	memset(cursor, 0, sizeof(*cursor));
    
    if (w > 16)
        w = 16;
    
    if (h > 16)
        h = 16;
    
	bytes = (w+7)/8;

	for ( row=0; row<h; ++row ) {
		memcpy(&cursor->curs.data[row], data, bytes);
		data += bytes;
	}
	for ( row=0; row<h; ++row ) {
		memcpy(&cursor->curs.mask[row], mask, bytes);
		mask += bytes;
	}
	cursor->curs.hotSpot.h = hot_x;
	cursor->curs.hotSpot.v = hot_y;
	
    return(cursor);
}

static int QZ_cursor_visible = 1;
    
static int QZ_ShowWMCursor (_THIS, WMcursor *cursor) { 

    if ( cursor == NULL) {
        if ( QZ_cursor_visible ) {
            HideCursor ();
            QZ_cursor_visible = 0;
        }
    }
    else {
        SetCursor(&cursor->curs);
        if ( ! QZ_cursor_visible ) {
            ShowCursor ();
            QZ_cursor_visible = 1;
        }
    }

    return 1;
}

static void  QZ_PrivateWarpCursor (_THIS, int fullscreen, int h, int x, int y) {

    CGPoint p;
    
    /* We require absolute screen coordiates for our warp */
    p.x = x;
    p.y = h - y;
        
    if ( fullscreen )
        /* Already absolute coordinates */
        CGDisplayMoveCursorToPoint(display_id, p);
    else {
        /* Convert to absolute screen coordinates */
        NSPoint base, screen;
        base = NSMakePoint (p.x, p.y);
        screen = [ qz_window convertBaseToScreen:base ];
        p.x = screen.x;
        p.y = device_height - screen.y;
        CGDisplayMoveCursorToPoint (display_id, p);
    }
}

static void QZ_WarpWMCursor     (_THIS, Uint16 x, Uint16 y) {
    
    /* Only allow warping when in foreground */
    if ( ! inForeground )
        return;
            
    /* Do the actual warp */
    QZ_PrivateWarpCursor (this, SDL_VideoSurface->flags & SDL_FULLSCREEN, 
        SDL_VideoSurface->h, x, y);
    
    /* Generate mouse moved event */
    SDL_PrivateMouseMotion (SDL_RELEASED, 0, x, y);
}

static void QZ_MoveWMCursor     (_THIS, int x, int y) { }
static void QZ_CheckMouseMode   (_THIS) { }

static void QZ_SetCaption    (_THIS, const char *title, const char *icon) {

    if ( qz_window != nil ) {
        NSString *string;
        if ( title != NULL ) {
            string = [ [ NSString alloc ] initWithCString:title ];
            [ qz_window setTitle:string ];
            [ string release ];
        }
        if ( icon != NULL ) {
            string = [ [ NSString alloc ] initWithCString:icon ];
            [ qz_window setMiniwindowTitle:string ];
            [ string release ];
        }
    }
}

static void QZ_SetIcon       (_THIS, SDL_Surface *icon, Uint8 *mask)
{
     NSBitmapImageRep *imgrep;
     NSImage *img;
     SDL_Surface *mergedSurface;
     Uint8 *surfPtr;
     int i,j,masksize;
     NSAutoreleasePool *pool;
     SDL_Rect rrect;
     NSSize imgSize = {icon->w, icon->h};
     pool = [ [ NSAutoreleasePool alloc ] init ];
     SDL_GetClipRect(icon, &rrect);
     /* create a big endian RGBA surface */
     mergedSurface = SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_SRCALPHA, 
icon->w, icon->h, 32, 0xff<<24, 0xff<<16, 0xff<<8, 0xff<<0);
     if (mergedSurface==NULL) { NSLog(@"Error creating surface for 
merge"); goto freePool; }
     if (SDL_BlitSurface(icon,&rrect,mergedSurface,&rrect)) {
         NSLog(@"Error blitting to mergedSurface");
         goto freePool;
     }
     if (mask) {
     masksize=icon->w*icon->h;
     surfPtr = (Uint8 *)mergedSurface->pixels;
     #define ALPHASHIFT 3
     for (i=0;i<masksize;i+=8)
         for (j=0;j<8;j++) 
surfPtr[ALPHASHIFT+((i+j)<<2)]=(mask[i>>3]&(1<<(7-j)))?0xFF:0x00;
     }
     imgrep = [[NSBitmapImageRep alloc] 
initWithBitmapDataPlanes:(unsigned char **)&mergedSurface->pixels 
pixelsWide:icon->w pixelsHigh:icon->h bitsPerSample:8 samplesPerPixel:4 
hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace 
bytesPerRow:icon->w<<2 bitsPerPixel:32];
     img = [[NSImage alloc] initWithSize:imgSize];
     [img addRepresentation: imgrep];
     [NSApp setApplicationIconImage:img];
     [img release];
     [imgrep release];
     SDL_FreeSurface(mergedSurface);
freePool:
     [pool release];
}

static int  QZ_IconifyWindow (_THIS) { 

    /* Bug! minimize erases the framebuffer */
    if ( ! [ qz_window isMiniaturized ] ) {
        [ qz_window miniaturize:nil ];
        return 1;
    }
    else {
        SDL_SetError ("qz_window already iconified");
        return 0;
    }
}

/*
static int  QZ_GetWMInfo  (_THIS, SDL_SysWMinfo *info) { 
    info->nsWindowPtr = qz_window;
    return 0; 
}*/

static SDL_GrabMode QZ_GrabInput (_THIS, SDL_GrabMode grab_mode) {

    switch (grab_mode) {
	case SDL_GRAB_QUERY:
            break;
	case SDL_GRAB_OFF:
            CGAssociateMouseAndMouseCursorPosition (1);
            currentGrabMode = SDL_GRAB_OFF;
            break;
	case SDL_GRAB_ON:
            QZ_WarpWMCursor (this, SDL_VideoSurface->w / 2, SDL_VideoSurface->h / 2);
            CGAssociateMouseAndMouseCursorPosition (0);
            currentGrabMode = SDL_GRAB_ON;
            break;
        case SDL_GRAB_FULLSCREEN:
            break;
    }
        
    return currentGrabMode;
}