Date: Sat, 19 Jan 2002 17:24:32 -0500 (EST)
authorSam Lantinga <slouken@libsdl.org>
Tue, 22 Jan 2002 18:46:28 +0000
changeset 272d1447a846d80
parent 271 9631db4d9ee1
child 273 72acb06d3721
Date: Sat, 19 Jan 2002 17:24:32 -0500 (EST)
From: Darrell Walisser <dwaliss1@purdue.edu>
Subject: SDL Quartz video update

-better mouse motion events
-fixed minification bugs (except OpenGL)
-fixed QZ_SetGamma for correct semantics
-fade/unfade display before/after rez switch
-experimental obscured-check/blind-copy code

The obscured code, while it speeds up window drawing substantially, isn't
ready yet. The reason is that there doesn't (yet) seem to be a way to know
when the window is dragged or when the window suddenly comes to the
foreground. Since Carbon windows seem to allow detection of such things, I
suspect it is possible through some window server API. Cocoa(NSWindow) has no
functions for such things, AFAIK.
src/video/quartz/SDL_QuartzEvents.m
src/video/quartz/SDL_QuartzVideo.h
src/video/quartz/SDL_QuartzVideo.m
src/video/quartz/SDL_QuartzWM.m
src/video/quartz/SDL_QuartzWindow.m
     1.1 --- a/src/video/quartz/SDL_QuartzEvents.m	Tue Jan 22 18:28:35 2002 +0000
     1.2 +++ b/src/video/quartz/SDL_QuartzEvents.m	Tue Jan 22 18:46:28 2002 +0000
     1.3 @@ -19,6 +19,7 @@
     1.4  	Sam Lantinga
     1.5  	slouken@libsdl.org
     1.6  */
     1.7 +#include <sys/time.h>
     1.8  
     1.9  #include "SDL_QuartzKeys.h"
    1.10  
    1.11 @@ -305,7 +306,13 @@
    1.12  
    1.13  static void QZ_PumpEvents (_THIS)
    1.14  {
    1.15 -	NSDate *distantPast;
    1.16 +	
    1.17 +        static NSPoint lastMouse;
    1.18 +        NSPoint mouse, saveMouse;
    1.19 +        Point qdMouse;
    1.20 +        CGMouseDelta dx, dy;
    1.21 +        
    1.22 +        NSDate *distantPast;
    1.23  	NSEvent *event;
    1.24  	NSRect winRect;
    1.25  	NSRect titleBarRect;
    1.26 @@ -314,10 +321,36 @@
    1.27  	pool = [ [ NSAutoreleasePool alloc ] init ];
    1.28  	distantPast = [ NSDate distantPast ];
    1.29  	
    1.30 -	winRect = NSMakeRect (0, 0, SDL_VideoSurface->w + 1, SDL_VideoSurface->h + 1);
    1.31 +	winRect = NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h);
    1.32  	titleBarRect = NSMakeRect ( 0, SDL_VideoSurface->h, SDL_VideoSurface->w,
    1.33  		SDL_VideoSurface->h + 22 );
    1.34 -			
    1.35 +	
    1.36 +        if (currentGrabMode != SDL_GRAB_ON) { /* if grabbed, the cursor can't move! (see fallback below) */
    1.37 +        
    1.38 +            /* 1/2 second after a warp, the mouse cannot move (don't ask me why) */
    1.39 +            /* So, approximate motion with CGGetLastMouseDelta, which still works, somehow */
    1.40 +            if (! warp_flag) {
    1.41 +            
    1.42 +                GetGlobalMouse (&qdMouse);  /* use Carbon since [ NSEvent mouseLocation ] is broken */
    1.43 +                mouse = NSMakePoint (qdMouse.h, qdMouse.v);
    1.44 +                saveMouse = mouse;
    1.45 +                
    1.46 +                if (mouse.x != lastMouse.x || mouse.y != lastMouse.y) {
    1.47 +                
    1.48 +                    QZ_PrivateCGToSDL (this, &mouse);
    1.49 +                    if (inForeground && NSPointInRect (mouse, winRect)) {
    1.50 +                        //printf ("Mouse Loc: (%f, %f)\n", mouse.x, mouse.y);
    1.51 +                        SDL_PrivateMouseMotion (0, 0, mouse.x, mouse.y);
    1.52 +                    }
    1.53 +                }
    1.54 +                lastMouse = saveMouse;
    1.55 +            }
    1.56 +        }
    1.57 +        
    1.58 +        /* accumulate any mouse events into one SDL mouse event */
    1.59 +        dx = 0;
    1.60 +        dy = 0;
    1.61 +        
    1.62  	do {
    1.63  	
    1.64  		/* Poll for an event. This will not block */
    1.65 @@ -330,22 +363,22 @@
    1.66  			BOOL isForGameWin;
    1.67  
    1.68  			#define DO_MOUSE_DOWN(button, sendToWindow) do {				 \
    1.69 -				if ( inForeground ) {										 \
    1.70 +				if ( inForeground ) {			                                 \
    1.71  					if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN) ||		 \
    1.72  						 NSPointInRect([event locationInWindow], winRect) )	 \
    1.73  						SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0);	 \
    1.74 -				}															 \
    1.75 -				else {														 \
    1.76 -					QZ_DoActivate (this);									 \
    1.77 -				}															 \
    1.78 -				[ NSApp sendEvent:event ];									 \
    1.79 +				}                                                                        \
    1.80 +				else {									 \
    1.81 +					QZ_DoActivate (this);                                            \
    1.82 +				}									 \
    1.83 +				[ NSApp sendEvent:event ];			                         \
    1.84  				} while(0)
    1.85  				
    1.86  			#define DO_MOUSE_UP(button, sendToWindow) do {					 \
    1.87  				if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN) ||			 \
    1.88 -					 !NSPointInRect([event locationInWindow], titleBarRect) )\
    1.89 -					SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0);	 \
    1.90 -				[ NSApp sendEvent:event ];									 \
    1.91 +					 !NSPointInRect([event locationInWindow], titleBarRect) )        \
    1.92 +					SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0);	         \
    1.93 +				[ NSApp sendEvent:event ];						 \
    1.94  				} while(0)
    1.95  
    1.96  			type = [ event type ];
    1.97 @@ -365,7 +398,7 @@
    1.98  					DO_MOUSE_DOWN (1, 1);
    1.99  				}
   1.100  				break;
   1.101 -			case 25:			   DO_MOUSE_DOWN (2, 0); break;
   1.102 +			case NSOtherMouseDown: DO_MOUSE_DOWN (2, 0); break;
   1.103  			case NSRightMouseDown: DO_MOUSE_DOWN (3, 0); break;	
   1.104  			case NSLeftMouseUp:
   1.105  			
   1.106 @@ -377,7 +410,7 @@
   1.107  					DO_MOUSE_UP (1, 1);
   1.108  				}
   1.109  				break;
   1.110 -			case 26:			   DO_MOUSE_UP (2, 0);	 break;
   1.111 +			case NSOtherMouseUp:   DO_MOUSE_UP (2, 0);	 break;
   1.112  			case NSRightMouseUp:   DO_MOUSE_UP (3, 0);	 break;
   1.113  			case NSSystemDefined:
   1.114  				//if ([event subtype] == 7) {
   1.115 @@ -389,30 +422,37 @@
   1.116  			case NSRightMouseDragged:
   1.117  			case 27:
   1.118  			case NSMouseMoved:
   1.119 -				if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN)
   1.120 -					|| NSPointInRect([event locationInWindow], winRect) )
   1.121 -				{
   1.122 -				   static int moves = 0;
   1.123 -				   NSPoint p;
   1.124 -			
   1.125 -				   if ( SDL_VideoSurface->flags & SDL_FULLSCREEN ) {
   1.126 -					   p = [ NSEvent mouseLocation ];
   1.127 -					   p.y = [[NSScreen mainScreen] frame].size.height - p.y;
   1.128 -				   } else {
   1.129 -					   p = [ event locationInWindow ];
   1.130 -					   p.y = SDL_VideoSurface->h - p.y;
   1.131 -				   }
   1.132 -
   1.133 -				   if ( (moves % 10) == 0 ) {
   1.134 -						SDL_PrivateMouseMotion (0, 0, p.x, p.y);
   1.135 -				   }
   1.136 -				   else {
   1.137 -						CGMouseDelta dx, dy;
   1.138 -						CGGetLastMouseDelta (&dx, &dy);
   1.139 -						SDL_PrivateMouseMotion (0, 1, dx, dy);
   1.140 -				   }
   1.141 -				   moves++;
   1.142 -				}
   1.143 +                            
   1.144 +                                if (currentGrabMode == SDL_GRAB_ON) { 
   1.145 +                                    
   1.146 +                                    /** 
   1.147 +                                     *  If input is grabbed, we'll wing it and try to send some mouse
   1.148 +                                     *  moved events with CGGetLastMouseDelta(). Not optimal, but better
   1.149 +                                     *  than nothing.
   1.150 +                                     **/ 
   1.151 +                                     CGMouseDelta dx1, dy1;
   1.152 +                                     CGGetLastMouseDelta (&dx1, &dy1);
   1.153 +                                     dx += dx1;
   1.154 +                                     dy += dy1;
   1.155 +                                }
   1.156 +                                else if (warp_flag) {
   1.157 +                                
   1.158 +                                    Uint32 ticks;
   1.159 +                
   1.160 +                                    ticks = SDL_GetTicks();
   1.161 +                                    if (ticks - warp_ticks < 150) {
   1.162 +                                    
   1.163 +                                        CGMouseDelta dx1, dy1;
   1.164 +                                        CGGetLastMouseDelta (&dx1, &dy1);
   1.165 +                                        dx += dx1;
   1.166 +                                        dy += dy1;
   1.167 +                                    }
   1.168 +                                    else {
   1.169 +                                        
   1.170 +                                        warp_flag = 0;
   1.171 +                                    }
   1.172 +                                }
   1.173 +                                
   1.174  				break;
   1.175  			case NSScrollWheel:
   1.176  				{
   1.177 @@ -435,8 +475,6 @@
   1.178  			case NSFlagsChanged:
   1.179  				QZ_DoModifiers( [ event modifierFlags ] );
   1.180  				break;
   1.181 -			/* case NSMouseEntered: break; */
   1.182 -			/* case NSMouseExited: break; */
   1.183  			case NSAppKitDefined:
   1.184  				switch ( [ event subtype ] ) {
   1.185  				case NSApplicationActivatedEventType:
   1.186 @@ -451,12 +489,17 @@
   1.187  			/* case NSApplicationDefined: break; */
   1.188  			/* case NSPeriodic: break; */
   1.189  			/* case NSCursorUpdate: break; */
   1.190 -			default:
   1.191 +                        
   1.192 +                        default:
   1.193  				[ NSApp sendEvent:event ];
   1.194  			}
   1.195  		}
   1.196  	  } while (event != nil);
   1.197  	
   1.198 +          /* check for accumulated mouse events */
   1.199 +          if (dx != 0 || dy != 0)
   1.200 +            SDL_PrivateMouseMotion (0, 1, dx, dy);
   1.201 +        
   1.202  	  [ pool release ];
   1.203  }
   1.204  
     2.1 --- a/src/video/quartz/SDL_QuartzVideo.h	Tue Jan 22 18:28:35 2002 +0000
     2.2 +++ b/src/video/quartz/SDL_QuartzVideo.h	Tue Jan 22 18:46:28 2002 +0000
     2.3 @@ -34,25 +34,28 @@
     2.4          - Multiple monitor support (currently only main display)
     2.5          - Accelerated blitting support
     2.6          - Set the window icon (dock icon when API is available)
     2.7 -        - Avoid erasing window on minimize, or disable minimize
     2.8 +        - Fix white OpenGL window on minimize
     2.9 +        - Find out what events should be sent/ignored if window is mimimized
    2.10 +        - Find a better way to deal with resolution/depth switch while app is running
    2.11 +        - Resizeable windows
    2.12 +        - Check accuracy of QZ_SetGamma()
    2.13      Problems:
    2.14          - OGL not working in full screen with software renderer
    2.15          - SetColors sets palette correctly but clears framebuffer
    2.16          - Crash in CG after several mode switches
    2.17 -        - Retained windows don't draw their title bar quite right (OS Bug)
    2.18 -        - Should I do depth switching for windowed modes? - No, not usually.
    2.19 -        - Launch times are slow, maybe prebinding will help
    2.20 -        - Direct framebuffer access has some artifacts, maybe a driver issue
    2.21 -        - Cursor in 8 bit modes is screwy
    2.22 +        - Retained windows don't draw their title bar quite right (OS Bug) (not using retained windows)
    2.23 +        - Cursor in 8 bit modes is screwy (might just be Radeon PCI bug)
    2.24 +        - Warping cursor delays mouse events for a fraction of a second,
    2.25 +          there is a hack around this that helps a bit
    2.26  */
    2.27  
    2.28 -#include <ApplicationServices/ApplicationServices.h>
    2.29 +#include <Cocoa/Cocoa.h>
    2.30  #include <OpenGL/OpenGL.h>
    2.31 -#include <Cocoa/Cocoa.h>
    2.32  #include <Carbon/Carbon.h>
    2.33  
    2.34  #include "SDL_video.h"
    2.35  #include "SDL_error.h"
    2.36 +#include "SDL_timer.h"
    2.37  #include "SDL_syswm.h"
    2.38  #include "SDL_sysvideo.h"
    2.39  #include "SDL_pixels_c.h"
    2.40 @@ -71,21 +74,34 @@
    2.41  }
    2.42  @end
    2.43  
    2.44 +/* Structure for rez switch gamma fades */
    2.45 +/* We can hide the monitor flicker by setting the gamma tables to 0 */
    2.46 +#define QZ_GAMMA_TABLE_SIZE 256
    2.47 +
    2.48 +typedef struct {
    2.49 +
    2.50 +    CGGammaValue red[QZ_GAMMA_TABLE_SIZE];
    2.51 +    CGGammaValue green[QZ_GAMMA_TABLE_SIZE];
    2.52 +    CGGammaValue blue[QZ_GAMMA_TABLE_SIZE];
    2.53 +
    2.54 +} SDL_QuartzGammaTable;
    2.55 +
    2.56 +/* Main driver structure to store required state information */
    2.57  typedef struct SDL_PrivateVideoData {
    2.58  
    2.59 -    CGDirectDisplayID  display; /* 0 == main display */
    2.60 -    CFDictionaryRef    mode;
    2.61 -    CFDictionaryRef    save_mode;
    2.62 -    CFArrayRef         mode_list;
    2.63 -    CGDirectPaletteRef palette;
    2.64 -    NSOpenGLContext    *gl_context;
    2.65 -    Uint32             width, height, bpp;
    2.66 -    Uint32             flags;
    2.67 -    SDL_bool           video_is_set; /* tell if the video mode was set */
    2.68 -    
    2.69 -    /* Window-only fields */
    2.70 -    NSWindow        *window;
    2.71 -    NSQuickDrawView *view;
    2.72 +    CGDirectDisplayID  display;            /* 0 == main display (only support single display) */
    2.73 +    CFDictionaryRef    mode;               /* current mode of the display */
    2.74 +    CFDictionaryRef    save_mode;          /* original mode of the display */
    2.75 +    CFArrayRef         mode_list;          /* list of available fullscreen modes */
    2.76 +    CGDirectPaletteRef palette;            /* palette of an 8-bit display */
    2.77 +    NSOpenGLContext    *gl_context;        /* object that represents an OpenGL rendering context */
    2.78 +    Uint32             width, height, bpp; /* frequently used data about the display */
    2.79 +    Uint32             flags;              /* flags for mode, for teardown purposes */
    2.80 +    Uint32             video_set;          /* boolean; indicates if video was set correctly */
    2.81 +    Uint32             warp_flag;          /* boolean; notify to event loop that a warp just occured */
    2.82 +    Uint32             warp_ticks;         /* timestamp when the warp occured */
    2.83 +    NSWindow           *window;            /* Cocoa window to implement the SDL window */
    2.84 +    NSQuickDrawView    *view;              /* the window's view; draw 2D into this view */
    2.85      
    2.86  } SDL_PrivateVideoData ;
    2.87  
    2.88 @@ -95,21 +111,68 @@
    2.89  #define save_mode (this->hidden->save_mode)
    2.90  #define mode_list (this->hidden->mode_list)
    2.91  #define palette (this->hidden->palette)
    2.92 -#define glcontext (this->hidden->glcontext)
    2.93 -#define objc_video (this->hidden->objc_video)
    2.94  #define gl_context (this->hidden->gl_context)
    2.95  #define device_width (this->hidden->width)
    2.96  #define device_height (this->hidden->height)
    2.97  #define device_bpp (this->hidden->bpp)
    2.98  #define mode_flags (this->hidden->flags)
    2.99 -#define video_set (this->hidden->video_is_set)
   2.100  #define qz_window (this->hidden->window)
   2.101 -#define windowView (this->hidden->view)
   2.102 +#define window_view (this->hidden->view)
   2.103 +#define video_set (this->hidden->video_set)
   2.104 +#define warp_ticks (this->hidden->warp_ticks)
   2.105 +#define warp_flag (this->hidden->warp_flag)
   2.106  
   2.107 -/* Interface for hardware fill not (yet) in the public API */
   2.108 -int CGSDisplayHWFill (CGDirectDisplayID id, unsigned int x, unsigned int y, 
   2.109 +/* Obscuring code: maximum number of windows above ours (inclusive) */
   2.110 +#define kMaxWindows 256
   2.111 +
   2.112 +/* Some of the Core Graphics Server API for obscuring code */
   2.113 +#define kCGSWindowLevelTop          2147483632
   2.114 +#define kCGSWindowLevelDockIconDrag 500
   2.115 +#define kCGSWindowLevelDockMenu     101
   2.116 +#define kCGSWindowLevelMenuIgnore    21
   2.117 +#define kCGSWindowLevelMenu          20
   2.118 +#define kCGSWindowLevelDockLabel     12
   2.119 +#define kCGSWindowLevelDockIcon      11
   2.120 +#define kCGSWindowLevelDock          10
   2.121 +#define kCGSWindowLevelUtility        3
   2.122 +#define kCGSWindowLevelNormal         0
   2.123 +
   2.124 +/* For completeness; We never use these window levels, they are always below us
   2.125 +#define kCGSWindowLevelMBarShadow -20
   2.126 +#define kCGSWindowLevelDesktopPicture -2147483647
   2.127 +#define kCGSWindowLevelDesktop        -2147483648
   2.128 +*/
   2.129 +
   2.130 +typedef CGError       CGSError;
   2.131 +typedef long	      CGSWindowCount;
   2.132 +typedef void *	      CGSConnectionID;
   2.133 +typedef int	      CGSWindowID;
   2.134 +typedef CGSWindowID*  CGSWindowIDList;
   2.135 +typedef CGWindowLevel CGSWindowLevel;
   2.136 +typedef NSRect        CGSRect;
   2.137 +
   2.138 +extern CGSConnectionID _CGSDefaultConnection ();
   2.139 +
   2.140 +extern CGSError CGSGetOnScreenWindowList (CGSConnectionID cid, 
   2.141 +                                          CGSConnectionID owner,
   2.142 +                                          CGSWindowCount listCapacity,
   2.143 +                                          CGSWindowIDList list,
   2.144 +                                          CGSWindowCount *listCount);
   2.145 +
   2.146 +extern CGSError CGSGetScreenRectForWindow (CGSConnectionID cid,
   2.147 +                                           CGSWindowID wid,
   2.148 +                                           CGSRect *rect);
   2.149 +
   2.150 +extern CGWindowLevel CGSGetWindowLevel (CGSConnectionID cid,
   2.151 +                                        CGSWindowID wid,
   2.152 +                                        CGSWindowLevel *level);
   2.153 +                                        
   2.154 +extern CGSError CGSDisplayHWFill (CGDirectDisplayID id, unsigned int x, unsigned int y, 
   2.155                        unsigned int w, unsigned int h, unsigned int color);
   2.156 -int CGSDisplayCanHWFill (CGDirectDisplayID id);
   2.157 +
   2.158 +extern CGSError CGSDisplayCanHWFill (CGDirectDisplayID id);
   2.159 +
   2.160 +extern CGSError CGSGetMouseEnabledFlags (CGSConnectionID cid, CGSWindowID wid, int *flags);
   2.161  
   2.162  /* Bootstrap functions */
   2.163  static int              QZ_Available ();
   2.164 @@ -156,7 +219,7 @@
   2.165  static int    QZ_GL_LoadLibrary    (_THIS, const char *location);
   2.166  
   2.167  /* Private function to warp the cursor (used internally) */
   2.168 -static void  QZ_PrivateWarpCursor (_THIS, int fullscreen, int h, int x, int y);
   2.169 +static void  QZ_PrivateWarpCursor (_THIS, int x, int y);
   2.170  
   2.171  /* Cursor and Mouse functions */
   2.172  static void         QZ_FreeWMCursor     (_THIS, WMcursor *cursor);
   2.173 @@ -177,3 +240,4 @@
   2.174  static int  QZ_IconifyWindow (_THIS);
   2.175  static SDL_GrabMode QZ_GrabInput (_THIS, SDL_GrabMode grab_mode);
   2.176  /*static int  QZ_GetWMInfo     (_THIS, SDL_SysWMinfo *info);*/
   2.177 +
     3.1 --- a/src/video/quartz/SDL_QuartzVideo.m	Tue Jan 22 18:28:35 2002 +0000
     3.2 +++ b/src/video/quartz/SDL_QuartzVideo.m	Tue Jan 22 18:46:28 2002 +0000
     3.3 @@ -32,9 +32,10 @@
     3.4  #include "SDL_QuartzEvents.m"
     3.5  #include "SDL_QuartzWindow.m"
     3.6  
     3.7 +
     3.8  /* Bootstrap binding, enables entry point into the driver */
     3.9  VideoBootStrap QZ_bootstrap = {
    3.10 -    "Quartz", "MacOS X CoreGraphics", QZ_Available, QZ_CreateDevice
    3.11 +    "Quartz", "Mac OS X CoreGraphics", QZ_Available, QZ_CreateDevice
    3.12  };
    3.13  
    3.14  /* Bootstrap functions */
    3.15 @@ -44,7 +45,7 @@
    3.16  
    3.17  static SDL_VideoDevice* QZ_CreateDevice (int device_index) {
    3.18  
    3.19 -   #pragma unused (device_index)
    3.20 +#pragma unused (device_index)
    3.21  
    3.22      SDL_VideoDevice *device;
    3.23      SDL_PrivateVideoData *hidden;
    3.24 @@ -57,7 +58,7 @@
    3.25  
    3.26      memset (device, 0, sizeof (*device) );
    3.27      memset (hidden, 0, sizeof (*hidden) );
    3.28 -    
    3.29 +
    3.30      device->hidden = hidden;
    3.31  
    3.32      device->VideoInit        = QZ_VideoInit;
    3.33 @@ -67,7 +68,7 @@
    3.34      device->SetColors        = QZ_SetColors;
    3.35      /* device->UpdateRects      = QZ_UpdateRects; this is determined by SetVideoMode() */
    3.36      device->VideoQuit        = QZ_VideoQuit;
    3.37 -    
    3.38 +
    3.39      device->LockHWSurface   = QZ_LockHWSurface;
    3.40      device->UnlockHWSurface = QZ_UnlockHWSurface;
    3.41      device->FreeHWSurface   = QZ_FreeHWSurface;
    3.42 @@ -83,7 +84,7 @@
    3.43      device->GL_MakeCurrent    = QZ_GL_MakeCurrent;
    3.44      device->GL_SwapBuffers    = QZ_GL_SwapBuffers;
    3.45      device->GL_LoadLibrary    = QZ_GL_LoadLibrary;
    3.46 -    
    3.47 +
    3.48      device->FreeWMCursor   = QZ_FreeWMCursor;
    3.49      device->CreateWMCursor = QZ_CreateWMCursor;
    3.50      device->ShowWMCursor   = QZ_ShowWMCursor;
    3.51 @@ -98,9 +99,9 @@
    3.52      device->IconifyWindow = QZ_IconifyWindow;
    3.53      /*device->GetWMInfo     = QZ_GetWMInfo;*/
    3.54      device->GrabInput     = QZ_GrabInput;
    3.55 -    
    3.56 +
    3.57      device->free = QZ_DeleteDevice;
    3.58 -    
    3.59 +
    3.60      return device;
    3.61  }
    3.62  
    3.63 @@ -112,30 +113,30 @@
    3.64  
    3.65  static int QZ_VideoInit (_THIS, SDL_PixelFormat *video_format) {
    3.66  
    3.67 -  /* Initialize the video settings; this data persists between mode switches */
    3.68 -  display_id = kCGDirectMainDisplay; 
    3.69 -  save_mode  = CGDisplayCurrentMode    (display_id);
    3.70 -  mode_list  = CGDisplayAvailableModes (display_id);
    3.71 -  palette    = CGPaletteCreateDefaultColorPalette ();
    3.72 -  
    3.73 -  /* Gather some information that is useful to know about the display */
    3.74 -  CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayBitsPerPixel), 
    3.75 -		    kCFNumberSInt32Type, &device_bpp);
    3.76 +    /* Initialize the video settings; this data persists between mode switches */
    3.77 +    display_id = kCGDirectMainDisplay;
    3.78 +    save_mode  = CGDisplayCurrentMode    (display_id);
    3.79 +    mode_list  = CGDisplayAvailableModes (display_id);
    3.80 +    palette    = CGPaletteCreateDefaultColorPalette ();
    3.81  
    3.82 -  CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayWidth),
    3.83 -                    kCFNumberSInt32Type, &device_width);
    3.84 -  
    3.85 -  CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayHeight),
    3.86 -                    kCFNumberSInt32Type, &device_height);
    3.87 +    /* Gather some information that is useful to know about the display */
    3.88 +    CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayBitsPerPixel),
    3.89 +                      kCFNumberSInt32Type, &device_bpp);
    3.90  
    3.91 -  video_format->BitsPerPixel = device_bpp;
    3.92 -  
    3.93 -  return 0;
    3.94 +    CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayWidth),
    3.95 +                      kCFNumberSInt32Type, &device_width);
    3.96 +
    3.97 +    CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayHeight),
    3.98 +                      kCFNumberSInt32Type, &device_height);
    3.99 +
   3.100 +    video_format->BitsPerPixel = device_bpp;
   3.101 +
   3.102 +    return 0;
   3.103  }
   3.104  
   3.105  static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format, Uint32 flags) {
   3.106      
   3.107 -    CFIndex num_modes = CFArrayGetCount (mode_list);
   3.108 +    CFIndex num_modes;
   3.109      CFIndex i;
   3.110  
   3.111      static SDL_Rect **list = NULL;
   3.112 @@ -157,6 +158,8 @@
   3.113        list = NULL;
   3.114      }
   3.115      
   3.116 +    num_modes = CFArrayGetCount (mode_list);
   3.117 +
   3.118      /* Build list of modes with the requested bpp */
   3.119      for (i = 0; i < num_modes; i++) {
   3.120     
   3.121 @@ -201,16 +204,18 @@
   3.122              
   3.123              list_size++;
   3.124  
   3.125 -            if ( list == NULL)
   3.126 -                list = (SDL_Rect**) malloc (sizeof(*list) * list_size+1);
   3.127 +            if (list == NULL)
   3.128 +                list = (SDL_Rect**) malloc (sizeof(*list) * (list_size+1) );
   3.129              else
   3.130 -                list = (SDL_Rect**) realloc (list, sizeof(*list) * list_size+1);
   3.131 +                list = (SDL_Rect**) realloc (list, sizeof(*list) * (list_size+1));
   3.132              
   3.133              rect = (SDL_Rect*) malloc (sizeof(**list));
   3.134              
   3.135 -            if (list == NULL || rect == NULL)
   3.136 +            if (list == NULL || rect == NULL) {
   3.137                  SDL_OutOfMemory ();
   3.138 -    
   3.139 +                return NULL;
   3.140 +            }
   3.141 +            
   3.142              rect->w = width;
   3.143              rect->h = height;
   3.144      
   3.145 @@ -241,43 +246,146 @@
   3.146      return list;
   3.147  }
   3.148  
   3.149 +/* Gamma functions to try to hide the flash from a rez switch */
   3.150 +/* Fade the display from normal to black */
   3.151 +/* Save gamma tables for fade back to normal */
   3.152 +static UInt32 QZ_FadeGammaOut (_THIS, SDL_QuartzGammaTable *table) {
   3.153 +
   3.154 +    CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE],
   3.155 +    greenTable[QZ_GAMMA_TABLE_SIZE],
   3.156 +    blueTable[QZ_GAMMA_TABLE_SIZE];
   3.157 +
   3.158 +    float percent;
   3.159 +    int j;
   3.160 +    int actual;
   3.161 +
   3.162 +    if ( (CGDisplayNoErr != CGGetDisplayTransferByTable
   3.163 +          (display_id, QZ_GAMMA_TABLE_SIZE,
   3.164 +           table->red, table->green, table->blue, &actual)) ||
   3.165 +         actual != QZ_GAMMA_TABLE_SIZE) {
   3.166 +
   3.167 +        return 1;
   3.168 +    }
   3.169 +
   3.170 +    memcpy (redTable, table->red, sizeof(redTable));
   3.171 +    memcpy (greenTable, table->green, sizeof(greenTable));
   3.172 +    memcpy (blueTable, table->blue, sizeof(greenTable));
   3.173 +
   3.174 +    for (percent = 1.0; percent >= 0.0; percent -= 0.01) {
   3.175 +
   3.176 +        for (j = 0; j < QZ_GAMMA_TABLE_SIZE; j++) {
   3.177 +
   3.178 +            redTable[j]   = redTable[j]   * percent;
   3.179 +            greenTable[j] = greenTable[j] * percent;
   3.180 +            blueTable[j]  = blueTable[j]  * percent;
   3.181 +        }
   3.182 +
   3.183 +        if (CGDisplayNoErr != CGSetDisplayTransferByTable
   3.184 +            (display_id, QZ_GAMMA_TABLE_SIZE,
   3.185 +             redTable, greenTable, blueTable)) {
   3.186 +
   3.187 +            CGDisplayRestoreColorSyncSettings();
   3.188 +            return 1;
   3.189 +        }
   3.190 +
   3.191 +        SDL_Delay (10);
   3.192 +    }
   3.193 +
   3.194 +    return 0;
   3.195 +}
   3.196 +
   3.197 +/* Fade the display from black to normal */
   3.198 +/* Restore previously saved gamma values */
   3.199 +static UInt32 QZ_FadeGammaIn (_THIS, SDL_QuartzGammaTable *table) {
   3.200 +
   3.201 +    CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE],
   3.202 +        greenTable[QZ_GAMMA_TABLE_SIZE],
   3.203 +        blueTable[QZ_GAMMA_TABLE_SIZE];
   3.204 +
   3.205 +    float percent;
   3.206 +    int j;
   3.207 +
   3.208 +    memset (redTable, 0, sizeof(redTable));
   3.209 +    memset (greenTable, 0, sizeof(greenTable));
   3.210 +    memset (blueTable, 0, sizeof(greenTable));
   3.211 +    
   3.212 +    for (percent = 0.0; percent <= 1.0; percent += 0.01) {
   3.213 +
   3.214 +        for (j = 0; j < QZ_GAMMA_TABLE_SIZE; j++) {
   3.215 +
   3.216 +            redTable[j]   = table->red[j]   * percent;
   3.217 +            greenTable[j] = table->green[j] * percent;
   3.218 +            blueTable[j]  = table->blue[j]  * percent;
   3.219 +        }
   3.220 +
   3.221 +        if (CGDisplayNoErr != CGSetDisplayTransferByTable
   3.222 +            (display_id, QZ_GAMMA_TABLE_SIZE,
   3.223 +             redTable, greenTable, blueTable)) {
   3.224 +
   3.225 +            CGDisplayRestoreColorSyncSettings();
   3.226 +            return 1;
   3.227 +        }
   3.228 +
   3.229 +        SDL_Delay (10);
   3.230 +    }
   3.231 +
   3.232 +    return 0;
   3.233 +}
   3.234 +
   3.235  static void QZ_UnsetVideoMode (_THIS) {
   3.236  
   3.237      /* Reset values that may change between switches */
   3.238      this->info.blit_fill = 0;
   3.239      this->FillHWRect     = NULL;
   3.240      this->UpdateRects    = NULL;
   3.241 -    
   3.242 -    /* Restore gamma settings */
   3.243 -    CGDisplayRestoreColorSyncSettings ();
   3.244     
   3.245 -    /* Restore original screen resolution */
   3.246 +    /* Release fullscreen resources */
   3.247      if ( mode_flags & SDL_FULLSCREEN ) {
   3.248 +
   3.249 +        SDL_QuartzGammaTable gamma_table;
   3.250 +        int gamma_error;
   3.251 +
   3.252 +        gamma_error = QZ_FadeGammaOut (this, &gamma_table);
   3.253 +
   3.254 +        /* Release the OpenGL context */
   3.255 +        /* Do this first to avoid trash on the display before fade */
   3.256 +        if ( mode_flags & SDL_OPENGL )
   3.257 +            QZ_TearDownOpenGL (this);
   3.258 +        
   3.259          if (mode_flags & SDL_OPENGL)
   3.260              CGLSetFullScreen(NULL);
   3.261 -            
   3.262 +
   3.263 +        /* Restore original screen resolution/bpp */
   3.264          CGDisplaySwitchToMode (display_id, save_mode);
   3.265          CGDisplayRelease (display_id);
   3.266 +        ShowMenuBar ();
   3.267 +        
   3.268 +        if (! gamma_error)
   3.269 +            QZ_FadeGammaIn (this, &gamma_table);
   3.270      }
   3.271 -    /* Release window mode data structures */
   3.272 +    /* Release window mode resources */
   3.273      else { 
   3.274          if ( (mode_flags & SDL_OPENGL) == 0 ) {
   3.275 -            UnlockPortBits ( [ windowView qdPort ] );
   3.276 -            [ windowView release  ];
   3.277 +            UnlockPortBits ( [ window_view qdPort ] );
   3.278 +            [ window_view release  ];
   3.279          }
   3.280          [ qz_window setContentView:nil ];
   3.281          [ qz_window setDelegate:nil ];
   3.282          [ qz_window close ];
   3.283 +        [ qz_window release ];
   3.284 +
   3.285 +        /* Release the OpenGL context */
   3.286 +        if ( mode_flags & SDL_OPENGL )
   3.287 +            QZ_TearDownOpenGL (this);
   3.288      }
   3.289 +
   3.290 +    /* Restore gamma settings */
   3.291 +    CGDisplayRestoreColorSyncSettings ();
   3.292      
   3.293      /* Set pixels to null (so other code doesn't try to free it) */
   3.294      if (this->screen != NULL)
   3.295          this->screen->pixels = NULL;
   3.296          
   3.297 -    /* Release the OpenGL context */
   3.298 -    if ( mode_flags & SDL_OPENGL )
   3.299 -        QZ_TearDownOpenGL (this);
   3.300 -        
   3.301      /* Ensure the cursor will be visible and working when we quit */
   3.302      CGDisplayShowCursor (display_id);
   3.303      CGAssociateMouseAndMouseCursorPosition (1);
   3.304 @@ -289,7 +397,9 @@
   3.305  static SDL_Surface* QZ_SetVideoFullScreen (_THIS, SDL_Surface *current, int width,
   3.306                                             int height, int bpp, Uint32 flags) {
   3.307      int exact_match;
   3.308 -
   3.309 +    int gamma_error;
   3.310 +    SDL_QuartzGammaTable gamma_table;
   3.311 +    
   3.312      /* See if requested mode exists */
   3.313      mode = CGDisplayBestModeForParameters (display_id, bpp, width, 
   3.314  					   height, &exact_match);
   3.315 @@ -301,34 +411,24 @@
   3.316          goto ERR_NO_MATCH;
   3.317      }
   3.318  
   3.319 +    /* Fade display to zero gamma */
   3.320 +    gamma_error = QZ_FadeGammaOut (this, &gamma_table);
   3.321 +
   3.322      /* Put up the blanking window (a window above all other windows) */
   3.323      if ( CGDisplayNoErr != CGDisplayCapture (display_id) ) {
   3.324          SDL_SetError ("Failed capturing display");
   3.325          goto ERR_NO_CAPTURE;
   3.326      }
   3.327 +
   3.328      
   3.329      /* Do the physical switch */
   3.330      if ( CGDisplayNoErr != CGDisplaySwitchToMode (display_id, mode) ) {
   3.331          SDL_SetError ("Failed switching display resolution");
   3.332          goto ERR_NO_SWITCH;
   3.333      }
   3.334 -    
   3.335 -    /* None of these methods seem to fix the fullscreen artifacts bug(s) */
   3.336 -#if USE_GDHANDLE
   3.337 -    SetGDevice(GetMainDevice());
   3.338 -    current->pitch = (**(**  GetMainDevice() ).gdPMap).rowBytes & 0x3FFF;
   3.339 -    current->pixels = (**(** GetMainDevice() ).gdPMap).baseAddr;
   3.340 -#elif USE_CREATEPORT
   3.341 -    device_port = CreateNewPortForCGDisplayID((Uint32*)display_id);
   3.342 -    SetPort (device_port);
   3.343 -    LockPortBits ( device_port );
   3.344 -    current->pixels = GetPixBaseAddr ( GetPortPixMap ( device_port ) );
   3.345 -    current->pitch  = GetPixRowBytes ( GetPortPixMap ( device_port ) );
   3.346 -    UnlockPortBits ( device_port );
   3.347 -#else
   3.348 +
   3.349      current->pixels = (Uint32*) CGDisplayBaseAddress (display_id);
   3.350      current->pitch  = CGDisplayBytesPerRow (display_id);
   3.351 -#endif
   3.352  
   3.353      current->flags = 0;
   3.354      current->w = width;
   3.355 @@ -354,7 +454,7 @@
   3.356          CGLContextObj ctx;
   3.357          
   3.358          if ( ! QZ_SetupOpenGL (this, bpp, flags) ) {
   3.359 -            return NULL;
   3.360 +            goto ERR_NO_GL;
   3.361          }
   3.362         
   3.363          ctx = [ gl_context cglContext ];
   3.364 @@ -367,22 +467,30 @@
   3.365          }
   3.366           
   3.367          [ gl_context makeCurrentContext];
   3.368 +
   3.369 +        glClear (GL_COLOR_BUFFER_BIT);
   3.370 +
   3.371 +        [ gl_context flushBuffer ];
   3.372          
   3.373          current->flags |= SDL_OPENGL;
   3.374      }
   3.375  
   3.376      /* If we don't hide menu bar, it will get events and interrupt the program */
   3.377      HideMenuBar ();
   3.378 +
   3.379 +    /* Fade the display to original gamma */
   3.380 +    if (! gamma_error )
   3.381 +        QZ_FadeGammaIn (this, &gamma_table);
   3.382      
   3.383      /* Save the flags to ensure correct tear-down */
   3.384      mode_flags = current->flags;
   3.385      
   3.386      return current;
   3.387  
   3.388 - /* Since the blanking window covers *all* windows (even force quit) correct recovery is crutial */
   3.389 + /* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */
   3.390   ERR_NO_GL:      CGDisplaySwitchToMode (display_id, save_mode);
   3.391   ERR_NO_SWITCH:  CGDisplayRelease (display_id);
   3.392 - ERR_NO_CAPTURE:
   3.393 + ERR_NO_CAPTURE: if (!gamma_error) { QZ_FadeGammaIn (this, &gamma_table); }
   3.394   ERR_NO_MATCH:	return NULL;
   3.395  }
   3.396  
   3.397 @@ -440,16 +548,17 @@
   3.398      /* For 2D, we set the content view to a NSQuickDrawView */
   3.399      else {
   3.400      
   3.401 -        windowView = [ [ NSQuickDrawView alloc ] init ];
   3.402 -        [ qz_window setContentView:windowView ];
   3.403 +        window_view = [ [ SDL_QuartzWindowView alloc ] init ];
   3.404 +        [ qz_window setContentView:window_view ];
   3.405          [ qz_window makeKeyAndOrderFront:nil ];    
   3.406          
   3.407 -        LockPortBits ( [ windowView qdPort ] );
   3.408 -        current->pixels = GetPixBaseAddr ( GetPortPixMap ( [ windowView qdPort ] ) );
   3.409 -        current->pitch  = GetPixRowBytes ( GetPortPixMap ( [ windowView qdPort ] ) );
   3.410 -            
   3.411 +        LockPortBits ( [ window_view qdPort ] );
   3.412 +        current->pixels = GetPixBaseAddr ( GetPortPixMap ( [ window_view qdPort ] ) );
   3.413 +        current->pitch  = GetPixRowBytes ( GetPortPixMap ( [ window_view qdPort ] ) );
   3.414 +        
   3.415          current->flags |= SDL_SWSURFACE;
   3.416          current->flags |= SDL_PREALLOC;
   3.417 +        
   3.418  	if ( flags & SDL_NOFRAME )
   3.419          	current->flags |= SDL_NOFRAME;
   3.420  	if ( flags & SDL_RESIZABLE )
   3.421 @@ -462,6 +571,10 @@
   3.422  
   3.423          this->UpdateRects = QZ_UpdateRects;
   3.424      }
   3.425 +    
   3.426 +    /* Save flags to ensure correct teardown */
   3.427 +    mode_flags = current->flags;
   3.428 +      
   3.429      return current;
   3.430  }
   3.431  
   3.432 @@ -482,7 +595,7 @@
   3.433      /* Setup windowed video */
   3.434      else {
   3.435          /* Force bpp to the device's bpp */
   3.436 -        bpp = current->format->BitsPerPixel;
   3.437 +        bpp = device_bpp;
   3.438          current = QZ_SetVideoWindowed (this, current, width, height, bpp, flags);
   3.439          if (current == NULL)
   3.440              return NULL;
   3.441 @@ -520,10 +633,7 @@
   3.442         	}
   3.443      }
   3.444      
   3.445 -    /* Warp mouse to origin in order to get passive mouse motion events started correctly */
   3.446 -    QZ_PrivateWarpCursor (this, current->flags & SDL_FULLSCREEN, height, 0, 0);
   3.447 -    
   3.448 -    /* Signal successful completion */
   3.449 +    /* Signal successful completion (used internally) */
   3.450      video_set = SDL_TRUE;
   3.451      
   3.452      return current;
   3.453 @@ -561,12 +671,293 @@
   3.454      #pragma unused(this,num_rects,rects)
   3.455  }
   3.456  
   3.457 +/** 
   3.458 + *  The obscured code is based on work by Matt Slot fprefect@ambrosiasw.com,
   3.459 + *  who supplied sample code for Carbon.
   3.460 + **/
   3.461 +static int QZ_IsWindowObscured (NSWindow *window) {
   3.462 +
   3.463 +//#define TEST_OBSCURED 1
   3.464 +
   3.465 +#if TEST_OBSCURED
   3.466 +    
   3.467 +    /*  In order to determine if a direct copy to the screen is possible,
   3.468 +       we must figure out if there are any windows covering ours (including shadows).
   3.469 +       This can be done by querying the window server about the on screen            
   3.470 +       windows for their screen rectangle and window level.                          
   3.471 +       The procedure used below is puts accuracy before speed; however, it aims to call 
   3.472 +       the window server the fewest number of times possible to keep things reasonable.
   3.473 +       In my testing on a 300mhz G3, this routine typically takes < 2 ms. -DW
   3.474 +    
   3.475 +        Notes:
   3.476 +            -Calls into the Window Server involve IPC which is slow.
   3.477 +            -Getting a rectangle seems slower than getting the window level
   3.478 +            -The window list we get back is in sorted order, top to bottom
   3.479 +            -On average, I suspect, most windows above ours are dock icon windows (hence optimization)
   3.480 +            -Some windows above ours are always there, and cannot move or obscure us (menu bar)
   3.481 +            
   3.482 +        Bugs:
   3.483 +            -no way (yet) to deactivate direct drawing when a window is dragged, 
   3.484 +               or suddenly obscured, so drawing continues and can produce garbage
   3.485 +               We need some kind of locking mechanism on window movement to prevent this
   3.486 +               
   3.487 +            -deactivated normal windows use activated normal 
   3.488 +               window shadows (slight inaccuraccy)
   3.489 +    */
   3.490 +    
   3.491 +    /* Cache the connection to the window server */
   3.492 +    static CGSConnectionID	cgsConnection = (CGSConnectionID) -1;
   3.493 +    
   3.494 +    /* Cache the dock icon windows */
   3.495 +    static CGSWindowID          dockIcons[kMaxWindows];
   3.496 +    static int                  numCachedDockIcons = 0;
   3.497 +    
   3.498 +    CGSWindowID		        windows[kMaxWindows];
   3.499 +    CGSWindowCount	        i, count;
   3.500 +    CGSWindowLevel	        winLevel;
   3.501 +    CGSRect			winRect;
   3.502 +
   3.503 +    CGSRect contentRect;
   3.504 +    int     windowNumber;
   3.505 +    //int     isMainWindow;
   3.506 +    int     firstDockIcon;    
   3.507 +    int     dockIconCacheMiss;
   3.508 +    int     windowContentOffset;
   3.509 +    
   3.510 +    int     obscured = SDL_TRUE;
   3.511 +        
   3.512 +    if ( [ window isVisible ] ) {
   3.513 +        
   3.514 +        /*  walk the window list looking for windows over top of 
   3.515 +                (or casting a shadow on) ours */
   3.516 +       
   3.517 +        /* Get a connection to the window server */
   3.518 +        /* Should probably be moved out into SetVideoMode() or InitVideo() */
   3.519 +        if (cgsConnection == (CGSConnectionID) -1) {
   3.520 +            cgsConnection = (CGSConnectionID) 0;
   3.521 +            cgsConnection = _CGSDefaultConnection ();
   3.522 +        }
   3.523 +        
   3.524 +        if (cgsConnection) { 
   3.525 +        
   3.526 +            if ( ! [ window styleMask ] & NSBorderlessWindowMask )
   3.527 +                windowContentOffset = 22;
   3.528 +            else
   3.529 +                windowContentOffset = 0;
   3.530 +                
   3.531 +            windowNumber = [ window windowNumber ];
   3.532 +            //isMainWindow = [ window isMainWindow ];
   3.533 +            
   3.534 +            /* The window list is sorted according to order on the screen */
   3.535 +            count = 0;
   3.536 +            CGSGetOnScreenWindowList (cgsConnection, 0, kMaxWindows, windows, &count);
   3.537 +            CGSGetScreenRectForWindow (cgsConnection, windowNumber, &contentRect);
   3.538 +    
   3.539 +            /* adjust rect for window title bar (if present) */
   3.540 +            contentRect.origin.y    += windowContentOffset;
   3.541 +            contentRect.size.height -= windowContentOffset;
   3.542 +            
   3.543 +            firstDockIcon = -1;
   3.544 +            dockIconCacheMiss = SDL_FALSE;
   3.545 +            
   3.546 +            /* The first window is always an empty window with level kCGSWindowLevelTop 
   3.547 +               so start at index 1 */
   3.548 +            for (i = 1; i < count; i++) {
   3.549 +                
   3.550 +                /* If we reach our window in the list, it cannot be obscured */
   3.551 +                if (windows[i] == windowNumber) {
   3.552 +                    
   3.553 +                    obscured = SDL_FALSE;
   3.554 +                    break;
   3.555 +                }
   3.556 +                else {
   3.557 +                    
   3.558 +                    float shadowSide;
   3.559 +                    float shadowTop;
   3.560 +                    float shadowBottom;
   3.561 +
   3.562 +                    CGSGetWindowLevel (cgsConnection, windows[i], &winLevel);
   3.563 +                    
   3.564 +                    if (winLevel == kCGSWindowLevelDockIcon) {
   3.565 +                    
   3.566 +                        int j;
   3.567 +                        
   3.568 +                        if (firstDockIcon < 0) {
   3.569 +                            
   3.570 +                            firstDockIcon = i;
   3.571 +                        
   3.572 +                            if (numCachedDockIcons > 0) {
   3.573 +                            
   3.574 +                                for (j = 0; j < numCachedDockIcons; j++) {
   3.575 +                            
   3.576 +                                    if (windows[i] == dockIcons[j])
   3.577 +                                        i++;
   3.578 +                                    else
   3.579 +                                        break;
   3.580 +                                }
   3.581 +                            
   3.582 +                                if (j != 0) {
   3.583 +                                 
   3.584 +                                    i--;
   3.585 +                                                                    
   3.586 +                                    if (j < numCachedDockIcons) {
   3.587 +                                        
   3.588 +                                        dockIconCacheMiss = SDL_TRUE;
   3.589 +                                    }
   3.590 +                                }
   3.591 +
   3.592 +                            }
   3.593 +                        }
   3.594 +                                               
   3.595 +                        continue;
   3.596 +                    }
   3.597 +                    else if (winLevel == kCGSWindowLevelMenuIgnore
   3.598 +                             /* winLevel == kCGSWindowLevelTop */) {
   3.599 +                     
   3.600 +                        continue; /* cannot obscure window */
   3.601 +                    }
   3.602 +                    else if (winLevel == kCGSWindowLevelDockMenu ||
   3.603 +                             winLevel == kCGSWindowLevelMenu) {
   3.604 +                     
   3.605 +                        shadowSide = 18;
   3.606 +                        shadowTop = 4;
   3.607 +                        shadowBottom = 22;   
   3.608 +                    }
   3.609 +                    else if (winLevel == kCGSWindowLevelUtility) {
   3.610 +                    
   3.611 +                        shadowSide = 8;
   3.612 +                        shadowTop = 4;
   3.613 +                        shadowBottom = 12;
   3.614 +                    }
   3.615 +                    else if (winLevel == kCGSWindowLevelNormal) {
   3.616 +                    
   3.617 +                        /* These numbers are for foreground windows,
   3.618 +                           they are too big (but will work) for background windows */
   3.619 +                        shadowSide = 20;
   3.620 +                        shadowTop = 10;
   3.621 +                        shadowBottom = 24;
   3.622 +                    }
   3.623 +                    else if (winLevel == kCGSWindowLevelDock) {
   3.624 +                    
   3.625 +                        /* Create dock icon cache */
   3.626 +                        if (numCachedDockIcons != (i-firstDockIcon) ||
   3.627 +                            dockIconCacheMiss) {
   3.628 +                        
   3.629 +                            numCachedDockIcons = i - firstDockIcon;
   3.630 +                            memcpy (dockIcons, &(windows[firstDockIcon]), 
   3.631 +                                    numCachedDockIcons * sizeof(*windows));
   3.632 +                        }
   3.633 +                        
   3.634 +                        /* no shadow */
   3.635 +                        shadowSide = 0;
   3.636 +                        shadowTop = 0;
   3.637 +                        shadowBottom = 0;
   3.638 +                    }
   3.639 +                    else {
   3.640 +                    
   3.641 +                        /*   kCGSWindowLevelDockLabel,
   3.642 +                             kCGSWindowLevelDock,
   3.643 +                             kOther??? */
   3.644 +                        
   3.645 +                        /* no shadow */
   3.646 +                        shadowSide = 0;
   3.647 +                        shadowTop = 0;
   3.648 +                        shadowBottom = 0;
   3.649 +                    }
   3.650 +                    
   3.651 +                    CGSGetScreenRectForWindow (cgsConnection, windows[i], &winRect);
   3.652 +                    
   3.653 +                    winRect.origin.x -= shadowSide;
   3.654 +                    winRect.origin.y -= shadowTop;
   3.655 +                    winRect.size.width += shadowSide;
   3.656 +                    winRect.size.height += shadowBottom;
   3.657 +                    
   3.658 +                    if (NSIntersectsRect (contentRect, winRect)) {
   3.659 +                    
   3.660 +                        obscured = SDL_TRUE;
   3.661 +                        break;
   3.662 +                    }
   3.663 +               
   3.664 +               } /* window was not our window */
   3.665 +            
   3.666 +            } /* iterate over windows */
   3.667 +            
   3.668 +        } /* get cgsConnection */
   3.669 +    
   3.670 +    } /* window is visible */
   3.671 +    
   3.672 +    return obscured;
   3.673 +#else
   3.674 +    return SDL_TRUE;
   3.675 +#endif
   3.676 +}
   3.677 +
   3.678  static void QZ_UpdateRects (_THIS, int numRects, SDL_Rect *rects) { 
   3.679 -    
   3.680 +
   3.681      if (SDL_VideoSurface->flags & SDL_OPENGLBLIT) {
   3.682          QZ_GL_SwapBuffers (this);
   3.683      }
   3.684 +    else if ( [ qz_window isMiniaturized ] && 
   3.685 +              ! (SDL_VideoSurface->flags & SDL_OPENGL)) {
   3.686 +    
   3.687 +        /** 
   3.688 +         * Set port alpha opaque so deminiaturize looks right
   3.689 +         * This isn't so nice, but there is no 
   3.690 +         * initial deminatureize notification (before demini starts)
   3.691 +         **/
   3.692 +        QZ_SetPortAlphaOpaque ([ [ qz_window contentView ] qdPort],
   3.693 +                                [ qz_window styleMask ] & NSBorderlessWindowMask);
   3.694 +    }
   3.695 +    else if ( ! QZ_IsWindowObscured (qz_window) ) {
   3.696 +        
   3.697 +        /* Use direct copy to flush contents to the display */
   3.698 +        CGrafPtr savePort;
   3.699 +        CGrafPtr dstPort, srcPort;
   3.700 +        const BitMap  *dstBits, *srcBits;
   3.701 +        Rect     dstRect, srcRect;      
   3.702 +        Point    offset;
   3.703 +        int i;
   3.704 +        
   3.705 +        GetPort (&savePort);
   3.706 +        
   3.707 +        dstPort = CreateNewPortForCGDisplayID ((UInt32)display_id);
   3.708 +        srcPort = [ window_view qdPort ];
   3.709 +        
   3.710 +        offset.h = 0;
   3.711 +        offset.v = 0;
   3.712 +        SetPort (srcPort);
   3.713 +        LocalToGlobal (&offset);
   3.714 +        
   3.715 +        SetPort (dstPort);
   3.716 +        
   3.717 +        LockPortBits (dstPort);
   3.718 +        LockPortBits (srcPort);
   3.719 +        
   3.720 +        dstBits = GetPortBitMapForCopyBits (dstPort);
   3.721 +        srcBits = GetPortBitMapForCopyBits (srcPort);
   3.722 +        
   3.723 +        for (i = 0; i < numRects; i++) {
   3.724 +            
   3.725 +            SetRect (&srcRect, rects[i].x, rects[i].y,
   3.726 +                     rects[i].x + rects[i].w,
   3.727 +                     rects[i].y + rects[i].h);
   3.728 +            
   3.729 +            SetRect (&dstRect,
   3.730 +                     rects[i].x + offset.h, 
   3.731 +                     rects[i].y + offset.v,
   3.732 +                     rects[i].x + rects[i].w + offset.h,
   3.733 +                     rects[i].y + rects[i].h + offset.v);
   3.734 +                        
   3.735 +            CopyBits (srcBits, dstBits,
   3.736 +                      &srcRect, &dstRect, srcCopy, NULL);
   3.737 +                        
   3.738 +        }
   3.739 +        
   3.740 +        SetPort (savePort);
   3.741 +    }
   3.742      else {
   3.743 +    
   3.744 +        /* Use QDFlushPortBuffer() to flush content to display */
   3.745          int i;
   3.746          RgnHandle dirty = NewRgn ();
   3.747          RgnHandle temp  = NewRgn ();
   3.748 @@ -582,7 +973,7 @@
   3.749          }
   3.750          
   3.751          /* Flush the dirty region */
   3.752 -        QDFlushPortBuffer ( [ windowView qdPort ], dirty );
   3.753 +        QDFlushPortBuffer ( [ window_view qdPort ], dirty );
   3.754          DisposeRgn (dirty);
   3.755          DisposeRgn (temp);
   3.756      }
   3.757 @@ -597,6 +988,7 @@
   3.758  static int  QZ_FillHWRect (_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color) {
   3.759  
   3.760      CGSDisplayHWFill (display_id, rect->x, rect->y, rect->w, rect->h, color);
   3.761 +
   3.762      return 0;
   3.763  }
   3.764  
   3.765 @@ -605,7 +997,8 @@
   3.766      return 1;
   3.767  }
   3.768  
   3.769 -static void QZ_UnlockHWSurface(_THIS, SDL_Surface *surface) { 
   3.770 +static void QZ_UnlockHWSurface(_THIS, SDL_Surface *surface) {
   3.771 +
   3.772  }
   3.773  
   3.774  static void QZ_FreeHWSurface (_THIS, SDL_Surface *surface) {
   3.775 @@ -621,24 +1014,43 @@
   3.776  static int QZ_SetGamma (_THIS, float red, float green, float blue) {
   3.777  
   3.778      const CGGammaValue min = 0.0, max = 1.0;
   3.779 +
   3.780 +    if (red == 0.0)
   3.781 +        red = FLT_MAX;
   3.782 +    else
   3.783 +        red = 1.0 / red;
   3.784 +
   3.785 +    if (green == 0.0)
   3.786 +        green = FLT_MAX;
   3.787 +    else
   3.788 +        green = 1.0 / green;
   3.789 +
   3.790 +    if (blue == 0.0)
   3.791 +        blue = FLT_MAX;
   3.792 +    else
   3.793 +        blue  = 1.0 / blue;
   3.794      
   3.795 -    if ( CGDisplayNoErr != CGSetDisplayTransferByFormula 
   3.796 -        (display_id, min, max, red, min, max, green, min, max, blue) )
   3.797 +    if ( CGDisplayNoErr == CGSetDisplayTransferByFormula 
   3.798 +        (display_id, min, max, red, min, max, green, min, max, blue) ) {
   3.799 +            
   3.800 +        return 0;
   3.801 +    }
   3.802 +    else {
   3.803 +    
   3.804          return -1;
   3.805 -    
   3.806 -    return 0;
   3.807 +    }
   3.808  }
   3.809  
   3.810  static int QZ_GetGamma (_THIS, float *red, float *green, float *blue) {
   3.811  
   3.812      CGGammaValue dummy;
   3.813 -    if ( CGDisplayNoErr != CGGetDisplayTransferByFormula
   3.814 +    if ( CGDisplayNoErr == CGGetDisplayTransferByFormula
   3.815          (display_id, &dummy, &dummy, red, 
   3.816  	 &dummy, &dummy, green, &dummy, &dummy, blue) )
   3.817          
   3.818 +        return 0;
   3.819 +    else
   3.820          return -1;
   3.821 -    
   3.822 -    return 0;
   3.823  }
   3.824  
   3.825  static int QZ_SetGammaRamp (_THIS, Uint16 *ramp) {
   3.826 @@ -660,11 +1072,11 @@
   3.827     for (i=512; i < 768; i++)
   3.828       blueTable[i % 256] = ramp[i] / 65535.0;
   3.829       
   3.830 -    if ( CGDisplayNoErr != CGSetDisplayTransferByTable 
   3.831 +    if ( CGDisplayNoErr == CGSetDisplayTransferByTable 
   3.832              (display_id, tableSize, redTable, greenTable, blueTable) )        
   3.833 +        return 0;
   3.834 +    else
   3.835          return -1;
   3.836 -    
   3.837 -    return 0;
   3.838  }
   3.839  
   3.840  static int QZ_GetGammaRamp (_THIS, Uint16 *ramp) {
   3.841 @@ -695,7 +1107,8 @@
   3.842      return 0;    
   3.843  }
   3.844  
   3.845 -/* OpenGL helper functions */
   3.846 +/* OpenGL helper functions (used internally) */
   3.847 +
   3.848  static int QZ_SetupOpenGL (_THIS, int bpp, Uint32 flags) {
   3.849  
   3.850      NSOpenGLPixelFormatAttribute attr[32];
   3.851 @@ -761,6 +1174,7 @@
   3.852      [ gl_context release ];
   3.853  }
   3.854  
   3.855 +
   3.856  /* SDL OpenGL functions */
   3.857  
   3.858  static int    QZ_GL_LoadLibrary    (_THIS, const char *location) {
   3.859 @@ -805,6 +1219,7 @@
   3.860      
   3.861      CGLGetParameter (ctx, param, (long*)value);
   3.862  */
   3.863 +
   3.864      *value = -1;
   3.865      return -1;
   3.866  }
   3.867 @@ -817,3 +1232,5 @@
   3.868  static void   QZ_GL_SwapBuffers    (_THIS) {
   3.869      [ gl_context flushBuffer ];
   3.870  }
   3.871 +
   3.872 +
     4.1 --- a/src/video/quartz/SDL_QuartzWM.m	Tue Jan 22 18:28:35 2002 +0000
     4.2 +++ b/src/video/quartz/SDL_QuartzWM.m	Tue Jan 22 18:46:28 2002 +0000
     4.3 @@ -87,40 +87,112 @@
     4.4      return 1;
     4.5  }
     4.6  
     4.7 -static void  QZ_PrivateWarpCursor (_THIS, int fullscreen, int h, int x, int y) {
     4.8 +/**
     4.9 + * Coordinate conversion functions, for convenience
    4.10 + * Cocoa sets the origin at the lower left corner of the window/screen
    4.11 + * SDL, CoreGraphics/WindowServer, and QuickDraw use the origin at the upper left corner
    4.12 + * The routines were written so they could be called before SetVideoMode() has finished;
    4.13 + * this might have limited usefulness at the moment, but the extra cost is trivial.
    4.14 + **/
    4.15  
    4.16 -    CGPoint p;
    4.17 +/* Convert Cocoa screen coordinate to Cocoa window coordinate */
    4.18 +static void QZ_PrivateGlobalToLocal (_THIS, NSPoint *p) {
    4.19 +
    4.20 +    *p = [ qz_window convertScreenToBase:*p ];
    4.21 +}
    4.22 +
    4.23 +
    4.24 +/* Convert Cocoa window coordinate to Cocoa screen coordinate */
    4.25 +static void QZ_PrivateLocalToGlobal (_THIS, NSPoint *p) {
    4.26 +
    4.27 +    *p = [ qz_window convertBaseToScreen:*p ];
    4.28 +}
    4.29 +
    4.30 +/* Convert SDL coordinate to Cocoa coordinate */
    4.31 +static void QZ_PrivateSDLToCocoa (_THIS, NSPoint *p) {
    4.32 +
    4.33 +    int height;
    4.34      
    4.35 -    /* We require absolute screen coordiates for our warp */
    4.36 -    p.x = x;
    4.37 -    p.y = h - y;
    4.38 +    if ( CGDisplayIsCaptured (display_id) ) { /* capture signals fullscreen */
    4.39 +    
    4.40 +        height = CGDisplayPixelsHigh (display_id);
    4.41 +    }
    4.42 +    else {
    4.43          
    4.44 -    if ( fullscreen )
    4.45 -        /* Already absolute coordinates */
    4.46 -        CGDisplayMoveCursorToPoint(display_id, p);
    4.47 -    else {
    4.48 -        /* Convert to absolute screen coordinates */
    4.49 -        NSPoint base, screen;
    4.50 -        base = NSMakePoint (p.x, p.y);
    4.51 -        screen = [ qz_window convertBaseToScreen:base ];
    4.52 -        p.x = screen.x;
    4.53 -        p.y = device_height - screen.y;
    4.54 -        CGDisplayMoveCursorToPoint (display_id, p);
    4.55 +        height = NSHeight ( [ qz_window frame ] );
    4.56 +        if ( [ qz_window styleMask ] & NSTitledWindowMask ) {
    4.57 +        
    4.58 +            height -= 22;
    4.59 +        }
    4.60 +    }
    4.61 +    
    4.62 +    p->y = height - p->y;
    4.63 +}
    4.64 +
    4.65 +/* Convert Cocoa coordinate to SDL coordinate */
    4.66 +static void QZ_PrivateCocoaToSDL (_THIS, NSPoint *p) {
    4.67 +
    4.68 +    QZ_PrivateSDLToCocoa (this, p);
    4.69 +}
    4.70 +
    4.71 +/* Convert SDL coordinate to window server (CoreGraphics) coordinate */
    4.72 +static CGPoint QZ_PrivateSDLToCG (_THIS, NSPoint *p) {
    4.73 +    
    4.74 +    CGPoint cgp;
    4.75 +    
    4.76 +    if ( ! CGDisplayIsCaptured (display_id) ) { /* not captured => not fullscreen => local coord */
    4.77 +    
    4.78 +        int height;
    4.79 +        
    4.80 +        QZ_PrivateSDLToCocoa (this, p);
    4.81 +        QZ_PrivateLocalToGlobal (this, p);
    4.82 +        
    4.83 +        height = CGDisplayPixelsHigh (display_id);
    4.84 +        p->y = height - p->y;
    4.85 +    }
    4.86 +    
    4.87 +    cgp.x = p->x;
    4.88 +    cgp.y = p->y;
    4.89 +    
    4.90 +    return cgp;
    4.91 +}
    4.92 +
    4.93 +/* Convert window server (CoreGraphics) coordinate to SDL coordinate */
    4.94 +static void QZ_PrivateCGToSDL (_THIS, NSPoint *p) {
    4.95 +            
    4.96 +    if ( ! CGDisplayIsCaptured (display_id) ) { /* not captured => not fullscreen => local coord */
    4.97 +    
    4.98 +        int height;
    4.99 +
   4.100 +        /* Convert CG Global to Cocoa Global */
   4.101 +        height = CGDisplayPixelsHigh (display_id);
   4.102 +        p->y = height - p->y;
   4.103 +
   4.104 +        QZ_PrivateGlobalToLocal (this, p);
   4.105 +        QZ_PrivateCocoaToSDL (this, p);
   4.106      }
   4.107  }
   4.108  
   4.109 -static void QZ_WarpWMCursor     (_THIS, Uint16 x, Uint16 y) {
   4.110 +static void  QZ_PrivateWarpCursor (_THIS, int x, int y) {
   4.111      
   4.112 +    NSPoint p;
   4.113 +    CGPoint cgp;
   4.114 +    
   4.115 +    p = NSMakePoint (x, y);
   4.116 +    cgp = QZ_PrivateSDLToCG (this, &p);   
   4.117 +    CGDisplayMoveCursorToPoint (display_id, cgp);
   4.118 +    warp_ticks = SDL_GetTicks();
   4.119 +    warp_flag = 1;
   4.120 +}
   4.121 +
   4.122 +static void QZ_WarpWMCursor (_THIS, Uint16 x, Uint16 y) {
   4.123 +
   4.124      /* Only allow warping when in foreground */
   4.125      if ( ! inForeground )
   4.126          return;
   4.127              
   4.128      /* Do the actual warp */
   4.129 -    QZ_PrivateWarpCursor (this, SDL_VideoSurface->flags & SDL_FULLSCREEN, 
   4.130 -        SDL_VideoSurface->h, x, y);
   4.131 -    
   4.132 -    /* Generate mouse moved event */
   4.133 -    SDL_PrivateMouseMotion (SDL_RELEASED, 0, x, y);
   4.134 +    QZ_PrivateWarpCursor (this, x, y);
   4.135  }
   4.136  
   4.137  static void QZ_MoveWMCursor     (_THIS, int x, int y) { }
   4.138 @@ -199,6 +271,17 @@
   4.139          return 0;
   4.140      }
   4.141  }
   4.142 +static int  QZ_IconifyWindow (_THIS) { 
   4.143 +
   4.144 +    if ( ! [ qz_window isMiniaturized ] ) {
   4.145 +        [ qz_window miniaturize:nil ];
   4.146 +        return 1;
   4.147 +    }
   4.148 +    else {
   4.149 +        SDL_SetError ("Quartz window already iconified");
   4.150 +        return 0;
   4.151 +    }
   4.152 +}
   4.153  
   4.154  /*
   4.155  static int  QZ_GetWMInfo  (_THIS, SDL_SysWMinfo *info) { 
   4.156 @@ -221,6 +304,7 @@
   4.157              currentGrabMode = SDL_GRAB_ON;
   4.158              break;
   4.159          case SDL_GRAB_FULLSCREEN:
   4.160 +            
   4.161              break;
   4.162      }
   4.163          
     5.1 --- a/src/video/quartz/SDL_QuartzWindow.m	Tue Jan 22 18:28:35 2002 +0000
     5.2 +++ b/src/video/quartz/SDL_QuartzWindow.m	Tue Jan 22 18:46:28 2002 +0000
     5.3 @@ -7,17 +7,74 @@
     5.4  - (void)display;
     5.5  @end
     5.6  
     5.7 +/**
     5.8 + * Function to set the opacity of window's pixels to 100% 
     5.9 + * The opacity is only used by the window server code that does the minimize effect
    5.10 + **/
    5.11 +static void QZ_SetPortAlphaOpaque (CGrafPtr port, Uint32 noTitleBar) {
    5.12 +    
    5.13 +    Uint32 *pixels;
    5.14 +    Uint32  rowPixels;
    5.15 +    Uint32  width, height;
    5.16 +    Uint32  bpp;
    5.17 +    PixMapHandle pixMap;
    5.18 +    Rect bounds;
    5.19 +    int i, j;
    5.20 +    
    5.21 +    pixMap = GetPortPixMap ( port );
    5.22 +    bpp = GetPixDepth ( pixMap );
    5.23 +    
    5.24 +    if (bpp == 32) {
    5.25 +    
    5.26 +        GetPortBounds ( port, &bounds );
    5.27 +        width = bounds.right - bounds.left;
    5.28 +        height = bounds.bottom - bounds.top;
    5.29 +        
    5.30 +        LockPortBits (port);
    5.31 +        
    5.32 +        pixels = (Uint32*) GetPixBaseAddr ( pixMap );
    5.33 +        rowPixels = GetPixRowBytes ( pixMap ) / 4;
    5.34 +        
    5.35 +        if (! noTitleBar) {
    5.36 +        
    5.37 +            /* offset for title bar */
    5.38 +            pixels += rowPixels * 22;
    5.39 +        }
    5.40 +            
    5.41 +        for (i = 0; i < height; i++)
    5.42 +            for (j = 0; j < width; j++) {
    5.43 +        
    5.44 +                pixels[ (i * rowPixels) + j ] |= 0xFF000000;
    5.45 +            }
    5.46 +            
    5.47 +        UnlockPortBits (port);
    5.48 +    }
    5.49 +}
    5.50 +
    5.51  @implementation SDL_QuartzWindow
    5.52  
    5.53 -/* These methods should be rewritten to fix the miniaturize bug */
    5.54 +/* override these methods to fix the miniaturize animation/dock icon bug */
    5.55  - (void)miniaturize:(id)sender
    5.56  {
    5.57 +    
    5.58 +    if (SDL_VideoSurface->flags & SDL_OPENGL) {
    5.59 +    
    5.60 +        /* Grab framebuffer and put into NSImage */
    5.61 +        /* [ qz_window setMiniwindowImage:image ]; */
    5.62 +    }
    5.63 +    else {
    5.64 +        
    5.65 +        QZ_SetPortAlphaOpaque ([ [ self contentView ] qdPort ], 
    5.66 +                               [ self styleMask ] & NSBorderlessWindowMask);
    5.67 +    }
    5.68 +    
    5.69      [ super miniaturize:sender ];
    5.70  }
    5.71  
    5.72 +/* this routine fires *after* deminiaturizing, so it might be useless to us */
    5.73  - (void)deminiaturize:(id)sender
    5.74  {
    5.75 -    [ super deminiaturize:sender ];
    5.76 +   [ super deminiaturize:sender ];
    5.77  }
    5.78  
    5.79  - (void)display
    5.80 @@ -38,4 +95,14 @@
    5.81      SDL_PrivateQuit();
    5.82      return NO;
    5.83  }
    5.84 +
    5.85  @end
    5.86 +
    5.87 +/* empty class; probably could be used to fix bugs in the future */
    5.88 +@interface SDL_QuartzWindowView : NSQuickDrawView
    5.89 +{}
    5.90 +@end
    5.91 +
    5.92 +@implementation SDL_QuartzWindowView
    5.93 +
    5.94 +@end
    5.95 \ No newline at end of file