Date: Sat, 19 Jan 2002 17:24:32 -0500 (EST)
authorSam Lantinga <slouken@libsdl.org>
Tue, 22 Jan 2002 18:46:28 +0000
changeset 272 d1447a846d80
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
--- a/src/video/quartz/SDL_QuartzEvents.m	Tue Jan 22 18:28:35 2002 +0000
+++ b/src/video/quartz/SDL_QuartzEvents.m	Tue Jan 22 18:46:28 2002 +0000
@@ -19,6 +19,7 @@
 	Sam Lantinga
 	slouken@libsdl.org
 */
+#include <sys/time.h>
 
 #include "SDL_QuartzKeys.h"
 
@@ -305,7 +306,13 @@
 
 static void QZ_PumpEvents (_THIS)
 {
-	NSDate *distantPast;
+	
+        static NSPoint lastMouse;
+        NSPoint mouse, saveMouse;
+        Point qdMouse;
+        CGMouseDelta dx, dy;
+        
+        NSDate *distantPast;
 	NSEvent *event;
 	NSRect winRect;
 	NSRect titleBarRect;
@@ -314,10 +321,36 @@
 	pool = [ [ NSAutoreleasePool alloc ] init ];
 	distantPast = [ NSDate distantPast ];
 	
-	winRect = NSMakeRect (0, 0, SDL_VideoSurface->w + 1, SDL_VideoSurface->h + 1);
+	winRect = NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h);
 	titleBarRect = NSMakeRect ( 0, SDL_VideoSurface->h, SDL_VideoSurface->w,
 		SDL_VideoSurface->h + 22 );
-			
+	
+        if (currentGrabMode != SDL_GRAB_ON) { /* if grabbed, the cursor can't move! (see fallback below) */
+        
+            /* 1/2 second after a warp, the mouse cannot move (don't ask me why) */
+            /* So, approximate motion with CGGetLastMouseDelta, which still works, somehow */
+            if (! warp_flag) {
+            
+                GetGlobalMouse (&qdMouse);  /* use Carbon since [ NSEvent mouseLocation ] is broken */
+                mouse = NSMakePoint (qdMouse.h, qdMouse.v);
+                saveMouse = mouse;
+                
+                if (mouse.x != lastMouse.x || mouse.y != lastMouse.y) {
+                
+                    QZ_PrivateCGToSDL (this, &mouse);
+                    if (inForeground && NSPointInRect (mouse, winRect)) {
+                        //printf ("Mouse Loc: (%f, %f)\n", mouse.x, mouse.y);
+                        SDL_PrivateMouseMotion (0, 0, mouse.x, mouse.y);
+                    }
+                }
+                lastMouse = saveMouse;
+            }
+        }
+        
+        /* accumulate any mouse events into one SDL mouse event */
+        dx = 0;
+        dy = 0;
+        
 	do {
 	
 		/* Poll for an event. This will not block */
@@ -330,22 +363,22 @@
 			BOOL isForGameWin;
 
 			#define DO_MOUSE_DOWN(button, sendToWindow) do {				 \
-				if ( inForeground ) {										 \
+				if ( inForeground ) {			                                 \
 					if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN) ||		 \
 						 NSPointInRect([event locationInWindow], winRect) )	 \
 						SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0);	 \
-				}															 \
-				else {														 \
-					QZ_DoActivate (this);									 \
-				}															 \
-				[ NSApp sendEvent:event ];									 \
+				}                                                                        \
+				else {									 \
+					QZ_DoActivate (this);                                            \
+				}									 \
+				[ NSApp sendEvent:event ];			                         \
 				} while(0)
 				
 			#define DO_MOUSE_UP(button, sendToWindow) do {					 \
 				if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN) ||			 \
-					 !NSPointInRect([event locationInWindow], titleBarRect) )\
-					SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0);	 \
-				[ NSApp sendEvent:event ];									 \
+					 !NSPointInRect([event locationInWindow], titleBarRect) )        \
+					SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0);	         \
+				[ NSApp sendEvent:event ];						 \
 				} while(0)
 
 			type = [ event type ];
@@ -365,7 +398,7 @@
 					DO_MOUSE_DOWN (1, 1);
 				}
 				break;
-			case 25:			   DO_MOUSE_DOWN (2, 0); break;
+			case NSOtherMouseDown: DO_MOUSE_DOWN (2, 0); break;
 			case NSRightMouseDown: DO_MOUSE_DOWN (3, 0); break;	
 			case NSLeftMouseUp:
 			
@@ -377,7 +410,7 @@
 					DO_MOUSE_UP (1, 1);
 				}
 				break;
-			case 26:			   DO_MOUSE_UP (2, 0);	 break;
+			case NSOtherMouseUp:   DO_MOUSE_UP (2, 0);	 break;
 			case NSRightMouseUp:   DO_MOUSE_UP (3, 0);	 break;
 			case NSSystemDefined:
 				//if ([event subtype] == 7) {
@@ -389,30 +422,37 @@
 			case NSRightMouseDragged:
 			case 27:
 			case NSMouseMoved:
-				if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN)
-					|| NSPointInRect([event locationInWindow], winRect) )
-				{
-				   static int moves = 0;
-				   NSPoint p;
-			
-				   if ( SDL_VideoSurface->flags & SDL_FULLSCREEN ) {
-					   p = [ NSEvent mouseLocation ];
-					   p.y = [[NSScreen mainScreen] frame].size.height - p.y;
-				   } else {
-					   p = [ event locationInWindow ];
-					   p.y = SDL_VideoSurface->h - p.y;
-				   }
-
-				   if ( (moves % 10) == 0 ) {
-						SDL_PrivateMouseMotion (0, 0, p.x, p.y);
-				   }
-				   else {
-						CGMouseDelta dx, dy;
-						CGGetLastMouseDelta (&dx, &dy);
-						SDL_PrivateMouseMotion (0, 1, dx, dy);
-				   }
-				   moves++;
-				}
+                            
+                                if (currentGrabMode == SDL_GRAB_ON) { 
+                                    
+                                    /** 
+                                     *  If input is grabbed, we'll wing it and try to send some mouse
+                                     *  moved events with CGGetLastMouseDelta(). Not optimal, but better
+                                     *  than nothing.
+                                     **/ 
+                                     CGMouseDelta dx1, dy1;
+                                     CGGetLastMouseDelta (&dx1, &dy1);
+                                     dx += dx1;
+                                     dy += dy1;
+                                }
+                                else if (warp_flag) {
+                                
+                                    Uint32 ticks;
+                
+                                    ticks = SDL_GetTicks();
+                                    if (ticks - warp_ticks < 150) {
+                                    
+                                        CGMouseDelta dx1, dy1;
+                                        CGGetLastMouseDelta (&dx1, &dy1);
+                                        dx += dx1;
+                                        dy += dy1;
+                                    }
+                                    else {
+                                        
+                                        warp_flag = 0;
+                                    }
+                                }
+                                
 				break;
 			case NSScrollWheel:
 				{
@@ -435,8 +475,6 @@
 			case NSFlagsChanged:
 				QZ_DoModifiers( [ event modifierFlags ] );
 				break;
-			/* case NSMouseEntered: break; */
-			/* case NSMouseExited: break; */
 			case NSAppKitDefined:
 				switch ( [ event subtype ] ) {
 				case NSApplicationActivatedEventType:
@@ -451,12 +489,17 @@
 			/* case NSApplicationDefined: break; */
 			/* case NSPeriodic: break; */
 			/* case NSCursorUpdate: break; */
-			default:
+                        
+                        default:
 				[ NSApp sendEvent:event ];
 			}
 		}
 	  } while (event != nil);
 	
+          /* check for accumulated mouse events */
+          if (dx != 0 || dy != 0)
+            SDL_PrivateMouseMotion (0, 1, dx, dy);
+        
 	  [ pool release ];
 }
 
--- a/src/video/quartz/SDL_QuartzVideo.h	Tue Jan 22 18:28:35 2002 +0000
+++ b/src/video/quartz/SDL_QuartzVideo.h	Tue Jan 22 18:46:28 2002 +0000
@@ -34,25 +34,28 @@
         - Multiple monitor support (currently only main display)
         - Accelerated blitting support
         - Set the window icon (dock icon when API is available)
-        - Avoid erasing window on minimize, or disable minimize
+        - Fix white OpenGL window on minimize
+        - Find out what events should be sent/ignored if window is mimimized
+        - Find a better way to deal with resolution/depth switch while app is running
+        - Resizeable windows
+        - Check accuracy of QZ_SetGamma()
     Problems:
         - OGL not working in full screen with software renderer
         - SetColors sets palette correctly but clears framebuffer
         - Crash in CG after several mode switches
-        - Retained windows don't draw their title bar quite right (OS Bug)
-        - Should I do depth switching for windowed modes? - No, not usually.
-        - Launch times are slow, maybe prebinding will help
-        - Direct framebuffer access has some artifacts, maybe a driver issue
-        - Cursor in 8 bit modes is screwy
+        - Retained windows don't draw their title bar quite right (OS Bug) (not using retained windows)
+        - Cursor in 8 bit modes is screwy (might just be Radeon PCI bug)
+        - Warping cursor delays mouse events for a fraction of a second,
+          there is a hack around this that helps a bit
 */
 
-#include <ApplicationServices/ApplicationServices.h>
+#include <Cocoa/Cocoa.h>
 #include <OpenGL/OpenGL.h>
-#include <Cocoa/Cocoa.h>
 #include <Carbon/Carbon.h>
 
 #include "SDL_video.h"
 #include "SDL_error.h"
+#include "SDL_timer.h"
 #include "SDL_syswm.h"
 #include "SDL_sysvideo.h"
 #include "SDL_pixels_c.h"
@@ -71,21 +74,34 @@
 }
 @end
 
+/* Structure for rez switch gamma fades */
+/* We can hide the monitor flicker by setting the gamma tables to 0 */
+#define QZ_GAMMA_TABLE_SIZE 256
+
+typedef struct {
+
+    CGGammaValue red[QZ_GAMMA_TABLE_SIZE];
+    CGGammaValue green[QZ_GAMMA_TABLE_SIZE];
+    CGGammaValue blue[QZ_GAMMA_TABLE_SIZE];
+
+} SDL_QuartzGammaTable;
+
+/* Main driver structure to store required state information */
 typedef struct SDL_PrivateVideoData {
 
-    CGDirectDisplayID  display; /* 0 == main display */
-    CFDictionaryRef    mode;
-    CFDictionaryRef    save_mode;
-    CFArrayRef         mode_list;
-    CGDirectPaletteRef palette;
-    NSOpenGLContext    *gl_context;
-    Uint32             width, height, bpp;
-    Uint32             flags;
-    SDL_bool           video_is_set; /* tell if the video mode was set */
-    
-    /* Window-only fields */
-    NSWindow        *window;
-    NSQuickDrawView *view;
+    CGDirectDisplayID  display;            /* 0 == main display (only support single display) */
+    CFDictionaryRef    mode;               /* current mode of the display */
+    CFDictionaryRef    save_mode;          /* original mode of the display */
+    CFArrayRef         mode_list;          /* list of available fullscreen modes */
+    CGDirectPaletteRef palette;            /* palette of an 8-bit display */
+    NSOpenGLContext    *gl_context;        /* object that represents an OpenGL rendering context */
+    Uint32             width, height, bpp; /* frequently used data about the display */
+    Uint32             flags;              /* flags for mode, for teardown purposes */
+    Uint32             video_set;          /* boolean; indicates if video was set correctly */
+    Uint32             warp_flag;          /* boolean; notify to event loop that a warp just occured */
+    Uint32             warp_ticks;         /* timestamp when the warp occured */
+    NSWindow           *window;            /* Cocoa window to implement the SDL window */
+    NSQuickDrawView    *view;              /* the window's view; draw 2D into this view */
     
 } SDL_PrivateVideoData ;
 
@@ -95,21 +111,68 @@
 #define save_mode (this->hidden->save_mode)
 #define mode_list (this->hidden->mode_list)
 #define palette (this->hidden->palette)
-#define glcontext (this->hidden->glcontext)
-#define objc_video (this->hidden->objc_video)
 #define gl_context (this->hidden->gl_context)
 #define device_width (this->hidden->width)
 #define device_height (this->hidden->height)
 #define device_bpp (this->hidden->bpp)
 #define mode_flags (this->hidden->flags)
-#define video_set (this->hidden->video_is_set)
 #define qz_window (this->hidden->window)
-#define windowView (this->hidden->view)
+#define window_view (this->hidden->view)
+#define video_set (this->hidden->video_set)
+#define warp_ticks (this->hidden->warp_ticks)
+#define warp_flag (this->hidden->warp_flag)
+
+/* Obscuring code: maximum number of windows above ours (inclusive) */
+#define kMaxWindows 256
+
+/* Some of the Core Graphics Server API for obscuring code */
+#define kCGSWindowLevelTop          2147483632
+#define kCGSWindowLevelDockIconDrag 500
+#define kCGSWindowLevelDockMenu     101
+#define kCGSWindowLevelMenuIgnore    21
+#define kCGSWindowLevelMenu          20
+#define kCGSWindowLevelDockLabel     12
+#define kCGSWindowLevelDockIcon      11
+#define kCGSWindowLevelDock          10
+#define kCGSWindowLevelUtility        3
+#define kCGSWindowLevelNormal         0
+
+/* For completeness; We never use these window levels, they are always below us
+#define kCGSWindowLevelMBarShadow -20
+#define kCGSWindowLevelDesktopPicture -2147483647
+#define kCGSWindowLevelDesktop        -2147483648
+*/
 
-/* Interface for hardware fill not (yet) in the public API */
-int CGSDisplayHWFill (CGDirectDisplayID id, unsigned int x, unsigned int y, 
+typedef CGError       CGSError;
+typedef long	      CGSWindowCount;
+typedef void *	      CGSConnectionID;
+typedef int	      CGSWindowID;
+typedef CGSWindowID*  CGSWindowIDList;
+typedef CGWindowLevel CGSWindowLevel;
+typedef NSRect        CGSRect;
+
+extern CGSConnectionID _CGSDefaultConnection ();
+
+extern CGSError CGSGetOnScreenWindowList (CGSConnectionID cid, 
+                                          CGSConnectionID owner,
+                                          CGSWindowCount listCapacity,
+                                          CGSWindowIDList list,
+                                          CGSWindowCount *listCount);
+
+extern CGSError CGSGetScreenRectForWindow (CGSConnectionID cid,
+                                           CGSWindowID wid,
+                                           CGSRect *rect);
+
+extern CGWindowLevel CGSGetWindowLevel (CGSConnectionID cid,
+                                        CGSWindowID wid,
+                                        CGSWindowLevel *level);
+                                        
+extern CGSError CGSDisplayHWFill (CGDirectDisplayID id, unsigned int x, unsigned int y, 
                       unsigned int w, unsigned int h, unsigned int color);
-int CGSDisplayCanHWFill (CGDirectDisplayID id);
+
+extern CGSError CGSDisplayCanHWFill (CGDirectDisplayID id);
+
+extern CGSError CGSGetMouseEnabledFlags (CGSConnectionID cid, CGSWindowID wid, int *flags);
 
 /* Bootstrap functions */
 static int              QZ_Available ();
@@ -156,7 +219,7 @@
 static int    QZ_GL_LoadLibrary    (_THIS, const char *location);
 
 /* Private function to warp the cursor (used internally) */
-static void  QZ_PrivateWarpCursor (_THIS, int fullscreen, int h, int x, int y);
+static void  QZ_PrivateWarpCursor (_THIS, int x, int y);
 
 /* Cursor and Mouse functions */
 static void         QZ_FreeWMCursor     (_THIS, WMcursor *cursor);
@@ -177,3 +240,4 @@
 static int  QZ_IconifyWindow (_THIS);
 static SDL_GrabMode QZ_GrabInput (_THIS, SDL_GrabMode grab_mode);
 /*static int  QZ_GetWMInfo     (_THIS, SDL_SysWMinfo *info);*/
+
--- a/src/video/quartz/SDL_QuartzVideo.m	Tue Jan 22 18:28:35 2002 +0000
+++ b/src/video/quartz/SDL_QuartzVideo.m	Tue Jan 22 18:46:28 2002 +0000
@@ -32,9 +32,10 @@
 #include "SDL_QuartzEvents.m"
 #include "SDL_QuartzWindow.m"
 
+
 /* Bootstrap binding, enables entry point into the driver */
 VideoBootStrap QZ_bootstrap = {
-    "Quartz", "MacOS X CoreGraphics", QZ_Available, QZ_CreateDevice
+    "Quartz", "Mac OS X CoreGraphics", QZ_Available, QZ_CreateDevice
 };
 
 /* Bootstrap functions */
@@ -44,7 +45,7 @@
 
 static SDL_VideoDevice* QZ_CreateDevice (int device_index) {
 
-   #pragma unused (device_index)
+#pragma unused (device_index)
 
     SDL_VideoDevice *device;
     SDL_PrivateVideoData *hidden;
@@ -57,7 +58,7 @@
 
     memset (device, 0, sizeof (*device) );
     memset (hidden, 0, sizeof (*hidden) );
-    
+
     device->hidden = hidden;
 
     device->VideoInit        = QZ_VideoInit;
@@ -67,7 +68,7 @@
     device->SetColors        = QZ_SetColors;
     /* device->UpdateRects      = QZ_UpdateRects; this is determined by SetVideoMode() */
     device->VideoQuit        = QZ_VideoQuit;
-    
+
     device->LockHWSurface   = QZ_LockHWSurface;
     device->UnlockHWSurface = QZ_UnlockHWSurface;
     device->FreeHWSurface   = QZ_FreeHWSurface;
@@ -83,7 +84,7 @@
     device->GL_MakeCurrent    = QZ_GL_MakeCurrent;
     device->GL_SwapBuffers    = QZ_GL_SwapBuffers;
     device->GL_LoadLibrary    = QZ_GL_LoadLibrary;
-    
+
     device->FreeWMCursor   = QZ_FreeWMCursor;
     device->CreateWMCursor = QZ_CreateWMCursor;
     device->ShowWMCursor   = QZ_ShowWMCursor;
@@ -98,9 +99,9 @@
     device->IconifyWindow = QZ_IconifyWindow;
     /*device->GetWMInfo     = QZ_GetWMInfo;*/
     device->GrabInput     = QZ_GrabInput;
-    
+
     device->free = QZ_DeleteDevice;
-    
+
     return device;
 }
 
@@ -112,30 +113,30 @@
 
 static int QZ_VideoInit (_THIS, SDL_PixelFormat *video_format) {
 
-  /* Initialize the video settings; this data persists between mode switches */
-  display_id = kCGDirectMainDisplay; 
-  save_mode  = CGDisplayCurrentMode    (display_id);
-  mode_list  = CGDisplayAvailableModes (display_id);
-  palette    = CGPaletteCreateDefaultColorPalette ();
-  
-  /* Gather some information that is useful to know about the display */
-  CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayBitsPerPixel), 
-		    kCFNumberSInt32Type, &device_bpp);
+    /* Initialize the video settings; this data persists between mode switches */
+    display_id = kCGDirectMainDisplay;
+    save_mode  = CGDisplayCurrentMode    (display_id);
+    mode_list  = CGDisplayAvailableModes (display_id);
+    palette    = CGPaletteCreateDefaultColorPalette ();
+
+    /* Gather some information that is useful to know about the display */
+    CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayBitsPerPixel),
+                      kCFNumberSInt32Type, &device_bpp);
 
-  CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayWidth),
-                    kCFNumberSInt32Type, &device_width);
-  
-  CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayHeight),
-                    kCFNumberSInt32Type, &device_height);
+    CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayWidth),
+                      kCFNumberSInt32Type, &device_width);
 
-  video_format->BitsPerPixel = device_bpp;
-  
-  return 0;
+    CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayHeight),
+                      kCFNumberSInt32Type, &device_height);
+
+    video_format->BitsPerPixel = device_bpp;
+
+    return 0;
 }
 
 static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format, Uint32 flags) {
     
-    CFIndex num_modes = CFArrayGetCount (mode_list);
+    CFIndex num_modes;
     CFIndex i;
 
     static SDL_Rect **list = NULL;
@@ -157,6 +158,8 @@
       list = NULL;
     }
     
+    num_modes = CFArrayGetCount (mode_list);
+
     /* Build list of modes with the requested bpp */
     for (i = 0; i < num_modes; i++) {
    
@@ -201,16 +204,18 @@
             
             list_size++;
 
-            if ( list == NULL)
-                list = (SDL_Rect**) malloc (sizeof(*list) * list_size+1);
+            if (list == NULL)
+                list = (SDL_Rect**) malloc (sizeof(*list) * (list_size+1) );
             else
-                list = (SDL_Rect**) realloc (list, sizeof(*list) * list_size+1);
+                list = (SDL_Rect**) realloc (list, sizeof(*list) * (list_size+1));
             
             rect = (SDL_Rect*) malloc (sizeof(**list));
             
-            if (list == NULL || rect == NULL)
+            if (list == NULL || rect == NULL) {
                 SDL_OutOfMemory ();
-    
+                return NULL;
+            }
+            
             rect->w = width;
             rect->h = height;
     
@@ -241,43 +246,146 @@
     return list;
 }
 
+/* Gamma functions to try to hide the flash from a rez switch */
+/* Fade the display from normal to black */
+/* Save gamma tables for fade back to normal */
+static UInt32 QZ_FadeGammaOut (_THIS, SDL_QuartzGammaTable *table) {
+
+    CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE],
+    greenTable[QZ_GAMMA_TABLE_SIZE],
+    blueTable[QZ_GAMMA_TABLE_SIZE];
+
+    float percent;
+    int j;
+    int actual;
+
+    if ( (CGDisplayNoErr != CGGetDisplayTransferByTable
+          (display_id, QZ_GAMMA_TABLE_SIZE,
+           table->red, table->green, table->blue, &actual)) ||
+         actual != QZ_GAMMA_TABLE_SIZE) {
+
+        return 1;
+    }
+
+    memcpy (redTable, table->red, sizeof(redTable));
+    memcpy (greenTable, table->green, sizeof(greenTable));
+    memcpy (blueTable, table->blue, sizeof(greenTable));
+
+    for (percent = 1.0; percent >= 0.0; percent -= 0.01) {
+
+        for (j = 0; j < QZ_GAMMA_TABLE_SIZE; j++) {
+
+            redTable[j]   = redTable[j]   * percent;
+            greenTable[j] = greenTable[j] * percent;
+            blueTable[j]  = blueTable[j]  * percent;
+        }
+
+        if (CGDisplayNoErr != CGSetDisplayTransferByTable
+            (display_id, QZ_GAMMA_TABLE_SIZE,
+             redTable, greenTable, blueTable)) {
+
+            CGDisplayRestoreColorSyncSettings();
+            return 1;
+        }
+
+        SDL_Delay (10);
+    }
+
+    return 0;
+}
+
+/* Fade the display from black to normal */
+/* Restore previously saved gamma values */
+static UInt32 QZ_FadeGammaIn (_THIS, SDL_QuartzGammaTable *table) {
+
+    CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE],
+        greenTable[QZ_GAMMA_TABLE_SIZE],
+        blueTable[QZ_GAMMA_TABLE_SIZE];
+
+    float percent;
+    int j;
+
+    memset (redTable, 0, sizeof(redTable));
+    memset (greenTable, 0, sizeof(greenTable));
+    memset (blueTable, 0, sizeof(greenTable));
+    
+    for (percent = 0.0; percent <= 1.0; percent += 0.01) {
+
+        for (j = 0; j < QZ_GAMMA_TABLE_SIZE; j++) {
+
+            redTable[j]   = table->red[j]   * percent;
+            greenTable[j] = table->green[j] * percent;
+            blueTable[j]  = table->blue[j]  * percent;
+        }
+
+        if (CGDisplayNoErr != CGSetDisplayTransferByTable
+            (display_id, QZ_GAMMA_TABLE_SIZE,
+             redTable, greenTable, blueTable)) {
+
+            CGDisplayRestoreColorSyncSettings();
+            return 1;
+        }
+
+        SDL_Delay (10);
+    }
+
+    return 0;
+}
+
 static void QZ_UnsetVideoMode (_THIS) {
 
     /* Reset values that may change between switches */
     this->info.blit_fill = 0;
     this->FillHWRect     = NULL;
     this->UpdateRects    = NULL;
-    
-    /* Restore gamma settings */
-    CGDisplayRestoreColorSyncSettings ();
    
-    /* Restore original screen resolution */
+    /* Release fullscreen resources */
     if ( mode_flags & SDL_FULLSCREEN ) {
+
+        SDL_QuartzGammaTable gamma_table;
+        int gamma_error;
+
+        gamma_error = QZ_FadeGammaOut (this, &gamma_table);
+
+        /* Release the OpenGL context */
+        /* Do this first to avoid trash on the display before fade */
+        if ( mode_flags & SDL_OPENGL )
+            QZ_TearDownOpenGL (this);
+        
         if (mode_flags & SDL_OPENGL)
             CGLSetFullScreen(NULL);
-            
+
+        /* Restore original screen resolution/bpp */
         CGDisplaySwitchToMode (display_id, save_mode);
         CGDisplayRelease (display_id);
+        ShowMenuBar ();
+        
+        if (! gamma_error)
+            QZ_FadeGammaIn (this, &gamma_table);
     }
-    /* Release window mode data structures */
+    /* Release window mode resources */
     else { 
         if ( (mode_flags & SDL_OPENGL) == 0 ) {
-            UnlockPortBits ( [ windowView qdPort ] );
-            [ windowView release  ];
+            UnlockPortBits ( [ window_view qdPort ] );
+            [ window_view release  ];
         }
         [ qz_window setContentView:nil ];
         [ qz_window setDelegate:nil ];
         [ qz_window close ];
+        [ qz_window release ];
+
+        /* Release the OpenGL context */
+        if ( mode_flags & SDL_OPENGL )
+            QZ_TearDownOpenGL (this);
     }
+
+    /* Restore gamma settings */
+    CGDisplayRestoreColorSyncSettings ();
     
     /* Set pixels to null (so other code doesn't try to free it) */
     if (this->screen != NULL)
         this->screen->pixels = NULL;
         
-    /* Release the OpenGL context */
-    if ( mode_flags & SDL_OPENGL )
-        QZ_TearDownOpenGL (this);
-        
     /* Ensure the cursor will be visible and working when we quit */
     CGDisplayShowCursor (display_id);
     CGAssociateMouseAndMouseCursorPosition (1);
@@ -289,7 +397,9 @@
 static SDL_Surface* QZ_SetVideoFullScreen (_THIS, SDL_Surface *current, int width,
                                            int height, int bpp, Uint32 flags) {
     int exact_match;
-
+    int gamma_error;
+    SDL_QuartzGammaTable gamma_table;
+    
     /* See if requested mode exists */
     mode = CGDisplayBestModeForParameters (display_id, bpp, width, 
 					   height, &exact_match);
@@ -301,34 +411,24 @@
         goto ERR_NO_MATCH;
     }
 
+    /* Fade display to zero gamma */
+    gamma_error = QZ_FadeGammaOut (this, &gamma_table);
+
     /* Put up the blanking window (a window above all other windows) */
     if ( CGDisplayNoErr != CGDisplayCapture (display_id) ) {
         SDL_SetError ("Failed capturing display");
         goto ERR_NO_CAPTURE;
     }
+
     
     /* Do the physical switch */
     if ( CGDisplayNoErr != CGDisplaySwitchToMode (display_id, mode) ) {
         SDL_SetError ("Failed switching display resolution");
         goto ERR_NO_SWITCH;
     }
-    
-    /* None of these methods seem to fix the fullscreen artifacts bug(s) */
-#if USE_GDHANDLE
-    SetGDevice(GetMainDevice());
-    current->pitch = (**(**  GetMainDevice() ).gdPMap).rowBytes & 0x3FFF;
-    current->pixels = (**(** GetMainDevice() ).gdPMap).baseAddr;
-#elif USE_CREATEPORT
-    device_port = CreateNewPortForCGDisplayID((Uint32*)display_id);
-    SetPort (device_port);
-    LockPortBits ( device_port );
-    current->pixels = GetPixBaseAddr ( GetPortPixMap ( device_port ) );
-    current->pitch  = GetPixRowBytes ( GetPortPixMap ( device_port ) );
-    UnlockPortBits ( device_port );
-#else
+
     current->pixels = (Uint32*) CGDisplayBaseAddress (display_id);
     current->pitch  = CGDisplayBytesPerRow (display_id);
-#endif
 
     current->flags = 0;
     current->w = width;
@@ -354,7 +454,7 @@
         CGLContextObj ctx;
         
         if ( ! QZ_SetupOpenGL (this, bpp, flags) ) {
-            return NULL;
+            goto ERR_NO_GL;
         }
        
         ctx = [ gl_context cglContext ];
@@ -367,22 +467,30 @@
         }
          
         [ gl_context makeCurrentContext];
+
+        glClear (GL_COLOR_BUFFER_BIT);
+
+        [ gl_context flushBuffer ];
         
         current->flags |= SDL_OPENGL;
     }
 
     /* If we don't hide menu bar, it will get events and interrupt the program */
     HideMenuBar ();
+
+    /* Fade the display to original gamma */
+    if (! gamma_error )
+        QZ_FadeGammaIn (this, &gamma_table);
     
     /* Save the flags to ensure correct tear-down */
     mode_flags = current->flags;
     
     return current;
 
- /* Since the blanking window covers *all* windows (even force quit) correct recovery is crutial */
+ /* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */
  ERR_NO_GL:      CGDisplaySwitchToMode (display_id, save_mode);
  ERR_NO_SWITCH:  CGDisplayRelease (display_id);
- ERR_NO_CAPTURE:
+ ERR_NO_CAPTURE: if (!gamma_error) { QZ_FadeGammaIn (this, &gamma_table); }
  ERR_NO_MATCH:	return NULL;
 }
 
@@ -440,16 +548,17 @@
     /* For 2D, we set the content view to a NSQuickDrawView */
     else {
     
-        windowView = [ [ NSQuickDrawView alloc ] init ];
-        [ qz_window setContentView:windowView ];
+        window_view = [ [ SDL_QuartzWindowView alloc ] init ];
+        [ qz_window setContentView:window_view ];
         [ qz_window makeKeyAndOrderFront:nil ];    
         
-        LockPortBits ( [ windowView qdPort ] );
-        current->pixels = GetPixBaseAddr ( GetPortPixMap ( [ windowView qdPort ] ) );
-        current->pitch  = GetPixRowBytes ( GetPortPixMap ( [ windowView qdPort ] ) );
-            
+        LockPortBits ( [ window_view qdPort ] );
+        current->pixels = GetPixBaseAddr ( GetPortPixMap ( [ window_view qdPort ] ) );
+        current->pitch  = GetPixRowBytes ( GetPortPixMap ( [ window_view qdPort ] ) );
+        
         current->flags |= SDL_SWSURFACE;
         current->flags |= SDL_PREALLOC;
+        
 	if ( flags & SDL_NOFRAME )
         	current->flags |= SDL_NOFRAME;
 	if ( flags & SDL_RESIZABLE )
@@ -462,6 +571,10 @@
 
         this->UpdateRects = QZ_UpdateRects;
     }
+    
+    /* Save flags to ensure correct teardown */
+    mode_flags = current->flags;
+      
     return current;
 }
 
@@ -482,7 +595,7 @@
     /* Setup windowed video */
     else {
         /* Force bpp to the device's bpp */
-        bpp = current->format->BitsPerPixel;
+        bpp = device_bpp;
         current = QZ_SetVideoWindowed (this, current, width, height, bpp, flags);
         if (current == NULL)
             return NULL;
@@ -520,10 +633,7 @@
        	}
     }
     
-    /* Warp mouse to origin in order to get passive mouse motion events started correctly */
-    QZ_PrivateWarpCursor (this, current->flags & SDL_FULLSCREEN, height, 0, 0);
-    
-    /* Signal successful completion */
+    /* Signal successful completion (used internally) */
     video_set = SDL_TRUE;
     
     return current;
@@ -561,12 +671,293 @@
     #pragma unused(this,num_rects,rects)
 }
 
+/** 
+ *  The obscured code is based on work by Matt Slot fprefect@ambrosiasw.com,
+ *  who supplied sample code for Carbon.
+ **/
+static int QZ_IsWindowObscured (NSWindow *window) {
+
+//#define TEST_OBSCURED 1
+
+#if TEST_OBSCURED
+    
+    /*  In order to determine if a direct copy to the screen is possible,
+       we must figure out if there are any windows covering ours (including shadows).
+       This can be done by querying the window server about the on screen            
+       windows for their screen rectangle and window level.                          
+       The procedure used below is puts accuracy before speed; however, it aims to call 
+       the window server the fewest number of times possible to keep things reasonable.
+       In my testing on a 300mhz G3, this routine typically takes < 2 ms. -DW
+    
+        Notes:
+            -Calls into the Window Server involve IPC which is slow.
+            -Getting a rectangle seems slower than getting the window level
+            -The window list we get back is in sorted order, top to bottom
+            -On average, I suspect, most windows above ours are dock icon windows (hence optimization)
+            -Some windows above ours are always there, and cannot move or obscure us (menu bar)
+            
+        Bugs:
+            -no way (yet) to deactivate direct drawing when a window is dragged, 
+               or suddenly obscured, so drawing continues and can produce garbage
+               We need some kind of locking mechanism on window movement to prevent this
+               
+            -deactivated normal windows use activated normal 
+               window shadows (slight inaccuraccy)
+    */
+    
+    /* Cache the connection to the window server */
+    static CGSConnectionID	cgsConnection = (CGSConnectionID) -1;
+    
+    /* Cache the dock icon windows */
+    static CGSWindowID          dockIcons[kMaxWindows];
+    static int                  numCachedDockIcons = 0;
+    
+    CGSWindowID		        windows[kMaxWindows];
+    CGSWindowCount	        i, count;
+    CGSWindowLevel	        winLevel;
+    CGSRect			winRect;
+
+    CGSRect contentRect;
+    int     windowNumber;
+    //int     isMainWindow;
+    int     firstDockIcon;    
+    int     dockIconCacheMiss;
+    int     windowContentOffset;
+    
+    int     obscured = SDL_TRUE;
+        
+    if ( [ window isVisible ] ) {
+        
+        /*  walk the window list looking for windows over top of 
+                (or casting a shadow on) ours */
+       
+        /* Get a connection to the window server */
+        /* Should probably be moved out into SetVideoMode() or InitVideo() */
+        if (cgsConnection == (CGSConnectionID) -1) {
+            cgsConnection = (CGSConnectionID) 0;
+            cgsConnection = _CGSDefaultConnection ();
+        }
+        
+        if (cgsConnection) { 
+        
+            if ( ! [ window styleMask ] & NSBorderlessWindowMask )
+                windowContentOffset = 22;
+            else
+                windowContentOffset = 0;
+                
+            windowNumber = [ window windowNumber ];
+            //isMainWindow = [ window isMainWindow ];
+            
+            /* The window list is sorted according to order on the screen */
+            count = 0;
+            CGSGetOnScreenWindowList (cgsConnection, 0, kMaxWindows, windows, &count);
+            CGSGetScreenRectForWindow (cgsConnection, windowNumber, &contentRect);
+    
+            /* adjust rect for window title bar (if present) */
+            contentRect.origin.y    += windowContentOffset;
+            contentRect.size.height -= windowContentOffset;
+            
+            firstDockIcon = -1;
+            dockIconCacheMiss = SDL_FALSE;
+            
+            /* The first window is always an empty window with level kCGSWindowLevelTop 
+               so start at index 1 */
+            for (i = 1; i < count; i++) {
+                
+                /* If we reach our window in the list, it cannot be obscured */
+                if (windows[i] == windowNumber) {
+                    
+                    obscured = SDL_FALSE;
+                    break;
+                }
+                else {
+                    
+                    float shadowSide;
+                    float shadowTop;
+                    float shadowBottom;
+
+                    CGSGetWindowLevel (cgsConnection, windows[i], &winLevel);
+                    
+                    if (winLevel == kCGSWindowLevelDockIcon) {
+                    
+                        int j;
+                        
+                        if (firstDockIcon < 0) {
+                            
+                            firstDockIcon = i;
+                        
+                            if (numCachedDockIcons > 0) {
+                            
+                                for (j = 0; j < numCachedDockIcons; j++) {
+                            
+                                    if (windows[i] == dockIcons[j])
+                                        i++;
+                                    else
+                                        break;
+                                }
+                            
+                                if (j != 0) {
+                                 
+                                    i--;
+                                                                    
+                                    if (j < numCachedDockIcons) {
+                                        
+                                        dockIconCacheMiss = SDL_TRUE;
+                                    }
+                                }
+
+                            }
+                        }
+                                               
+                        continue;
+                    }
+                    else if (winLevel == kCGSWindowLevelMenuIgnore
+                             /* winLevel == kCGSWindowLevelTop */) {
+                     
+                        continue; /* cannot obscure window */
+                    }
+                    else if (winLevel == kCGSWindowLevelDockMenu ||
+                             winLevel == kCGSWindowLevelMenu) {
+                     
+                        shadowSide = 18;
+                        shadowTop = 4;
+                        shadowBottom = 22;   
+                    }
+                    else if (winLevel == kCGSWindowLevelUtility) {
+                    
+                        shadowSide = 8;
+                        shadowTop = 4;
+                        shadowBottom = 12;
+                    }
+                    else if (winLevel == kCGSWindowLevelNormal) {
+                    
+                        /* These numbers are for foreground windows,
+                           they are too big (but will work) for background windows */
+                        shadowSide = 20;
+                        shadowTop = 10;
+                        shadowBottom = 24;
+                    }
+                    else if (winLevel == kCGSWindowLevelDock) {
+                    
+                        /* Create dock icon cache */
+                        if (numCachedDockIcons != (i-firstDockIcon) ||
+                            dockIconCacheMiss) {
+                        
+                            numCachedDockIcons = i - firstDockIcon;
+                            memcpy (dockIcons, &(windows[firstDockIcon]), 
+                                    numCachedDockIcons * sizeof(*windows));
+                        }
+                        
+                        /* no shadow */
+                        shadowSide = 0;
+                        shadowTop = 0;
+                        shadowBottom = 0;
+                    }
+                    else {
+                    
+                        /*   kCGSWindowLevelDockLabel,
+                             kCGSWindowLevelDock,
+                             kOther??? */
+                        
+                        /* no shadow */
+                        shadowSide = 0;
+                        shadowTop = 0;
+                        shadowBottom = 0;
+                    }
+                    
+                    CGSGetScreenRectForWindow (cgsConnection, windows[i], &winRect);
+                    
+                    winRect.origin.x -= shadowSide;
+                    winRect.origin.y -= shadowTop;
+                    winRect.size.width += shadowSide;
+                    winRect.size.height += shadowBottom;
+                    
+                    if (NSIntersectsRect (contentRect, winRect)) {
+                    
+                        obscured = SDL_TRUE;
+                        break;
+                    }
+               
+               } /* window was not our window */
+            
+            } /* iterate over windows */
+            
+        } /* get cgsConnection */
+    
+    } /* window is visible */
+    
+    return obscured;
+#else
+    return SDL_TRUE;
+#endif
+}
+
 static void QZ_UpdateRects (_THIS, int numRects, SDL_Rect *rects) { 
-    
+
     if (SDL_VideoSurface->flags & SDL_OPENGLBLIT) {
         QZ_GL_SwapBuffers (this);
     }
+    else if ( [ qz_window isMiniaturized ] && 
+              ! (SDL_VideoSurface->flags & SDL_OPENGL)) {
+    
+        /** 
+         * Set port alpha opaque so deminiaturize looks right
+         * This isn't so nice, but there is no 
+         * initial deminatureize notification (before demini starts)
+         **/
+        QZ_SetPortAlphaOpaque ([ [ qz_window contentView ] qdPort],
+                                [ qz_window styleMask ] & NSBorderlessWindowMask);
+    }
+    else if ( ! QZ_IsWindowObscured (qz_window) ) {
+        
+        /* Use direct copy to flush contents to the display */
+        CGrafPtr savePort;
+        CGrafPtr dstPort, srcPort;
+        const BitMap  *dstBits, *srcBits;
+        Rect     dstRect, srcRect;      
+        Point    offset;
+        int i;
+        
+        GetPort (&savePort);
+        
+        dstPort = CreateNewPortForCGDisplayID ((UInt32)display_id);
+        srcPort = [ window_view qdPort ];
+        
+        offset.h = 0;
+        offset.v = 0;
+        SetPort (srcPort);
+        LocalToGlobal (&offset);
+        
+        SetPort (dstPort);
+        
+        LockPortBits (dstPort);
+        LockPortBits (srcPort);
+        
+        dstBits = GetPortBitMapForCopyBits (dstPort);
+        srcBits = GetPortBitMapForCopyBits (srcPort);
+        
+        for (i = 0; i < numRects; i++) {
+            
+            SetRect (&srcRect, rects[i].x, rects[i].y,
+                     rects[i].x + rects[i].w,
+                     rects[i].y + rects[i].h);
+            
+            SetRect (&dstRect,
+                     rects[i].x + offset.h, 
+                     rects[i].y + offset.v,
+                     rects[i].x + rects[i].w + offset.h,
+                     rects[i].y + rects[i].h + offset.v);
+                        
+            CopyBits (srcBits, dstBits,
+                      &srcRect, &dstRect, srcCopy, NULL);
+                        
+        }
+        
+        SetPort (savePort);
+    }
     else {
+    
+        /* Use QDFlushPortBuffer() to flush content to display */
         int i;
         RgnHandle dirty = NewRgn ();
         RgnHandle temp  = NewRgn ();
@@ -582,7 +973,7 @@
         }
         
         /* Flush the dirty region */
-        QDFlushPortBuffer ( [ windowView qdPort ], dirty );
+        QDFlushPortBuffer ( [ window_view qdPort ], dirty );
         DisposeRgn (dirty);
         DisposeRgn (temp);
     }
@@ -597,6 +988,7 @@
 static int  QZ_FillHWRect (_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color) {
 
     CGSDisplayHWFill (display_id, rect->x, rect->y, rect->w, rect->h, color);
+
     return 0;
 }
 
@@ -605,7 +997,8 @@
     return 1;
 }
 
-static void QZ_UnlockHWSurface(_THIS, SDL_Surface *surface) { 
+static void QZ_UnlockHWSurface(_THIS, SDL_Surface *surface) {
+
 }
 
 static void QZ_FreeHWSurface (_THIS, SDL_Surface *surface) {
@@ -621,24 +1014,43 @@
 static int QZ_SetGamma (_THIS, float red, float green, float blue) {
 
     const CGGammaValue min = 0.0, max = 1.0;
+
+    if (red == 0.0)
+        red = FLT_MAX;
+    else
+        red = 1.0 / red;
+
+    if (green == 0.0)
+        green = FLT_MAX;
+    else
+        green = 1.0 / green;
+
+    if (blue == 0.0)
+        blue = FLT_MAX;
+    else
+        blue  = 1.0 / blue;
     
-    if ( CGDisplayNoErr != CGSetDisplayTransferByFormula 
-        (display_id, min, max, red, min, max, green, min, max, blue) )
+    if ( CGDisplayNoErr == CGSetDisplayTransferByFormula 
+        (display_id, min, max, red, min, max, green, min, max, blue) ) {
+            
+        return 0;
+    }
+    else {
+    
         return -1;
-    
-    return 0;
+    }
 }
 
 static int QZ_GetGamma (_THIS, float *red, float *green, float *blue) {
 
     CGGammaValue dummy;
-    if ( CGDisplayNoErr != CGGetDisplayTransferByFormula
+    if ( CGDisplayNoErr == CGGetDisplayTransferByFormula
         (display_id, &dummy, &dummy, red, 
 	 &dummy, &dummy, green, &dummy, &dummy, blue) )
         
+        return 0;
+    else
         return -1;
-    
-    return 0;
 }
 
 static int QZ_SetGammaRamp (_THIS, Uint16 *ramp) {
@@ -660,11 +1072,11 @@
    for (i=512; i < 768; i++)
      blueTable[i % 256] = ramp[i] / 65535.0;
      
-    if ( CGDisplayNoErr != CGSetDisplayTransferByTable 
+    if ( CGDisplayNoErr == CGSetDisplayTransferByTable 
             (display_id, tableSize, redTable, greenTable, blueTable) )        
+        return 0;
+    else
         return -1;
-    
-    return 0;
 }
 
 static int QZ_GetGammaRamp (_THIS, Uint16 *ramp) {
@@ -695,7 +1107,8 @@
     return 0;    
 }
 
-/* OpenGL helper functions */
+/* OpenGL helper functions (used internally) */
+
 static int QZ_SetupOpenGL (_THIS, int bpp, Uint32 flags) {
 
     NSOpenGLPixelFormatAttribute attr[32];
@@ -761,6 +1174,7 @@
     [ gl_context release ];
 }
 
+
 /* SDL OpenGL functions */
 
 static int    QZ_GL_LoadLibrary    (_THIS, const char *location) {
@@ -805,6 +1219,7 @@
     
     CGLGetParameter (ctx, param, (long*)value);
 */
+
     *value = -1;
     return -1;
 }
@@ -817,3 +1232,5 @@
 static void   QZ_GL_SwapBuffers    (_THIS) {
     [ gl_context flushBuffer ];
 }
+
+
--- a/src/video/quartz/SDL_QuartzWM.m	Tue Jan 22 18:28:35 2002 +0000
+++ b/src/video/quartz/SDL_QuartzWM.m	Tue Jan 22 18:46:28 2002 +0000
@@ -87,40 +87,112 @@
     return 1;
 }
 
-static void  QZ_PrivateWarpCursor (_THIS, int fullscreen, int h, int x, int y) {
+/**
+ * Coordinate conversion functions, for convenience
+ * Cocoa sets the origin at the lower left corner of the window/screen
+ * SDL, CoreGraphics/WindowServer, and QuickDraw use the origin at the upper left corner
+ * The routines were written so they could be called before SetVideoMode() has finished;
+ * this might have limited usefulness at the moment, but the extra cost is trivial.
+ **/
+
+/* Convert Cocoa screen coordinate to Cocoa window coordinate */
+static void QZ_PrivateGlobalToLocal (_THIS, NSPoint *p) {
 
-    CGPoint p;
+    *p = [ qz_window convertScreenToBase:*p ];
+}
+
+
+/* Convert Cocoa window coordinate to Cocoa screen coordinate */
+static void QZ_PrivateLocalToGlobal (_THIS, NSPoint *p) {
+
+    *p = [ qz_window convertBaseToScreen:*p ];
+}
+
+/* Convert SDL coordinate to Cocoa coordinate */
+static void QZ_PrivateSDLToCocoa (_THIS, NSPoint *p) {
+
+    int height;
     
-    /* We require absolute screen coordiates for our warp */
-    p.x = x;
-    p.y = h - y;
+    if ( CGDisplayIsCaptured (display_id) ) { /* capture signals fullscreen */
+    
+        height = CGDisplayPixelsHigh (display_id);
+    }
+    else {
+        
+        height = NSHeight ( [ qz_window frame ] );
+        if ( [ qz_window styleMask ] & NSTitledWindowMask ) {
         
-    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);
+            height -= 22;
+        }
+    }
+    
+    p->y = height - p->y;
+}
+
+/* Convert Cocoa coordinate to SDL coordinate */
+static void QZ_PrivateCocoaToSDL (_THIS, NSPoint *p) {
+
+    QZ_PrivateSDLToCocoa (this, p);
+}
+
+/* Convert SDL coordinate to window server (CoreGraphics) coordinate */
+static CGPoint QZ_PrivateSDLToCG (_THIS, NSPoint *p) {
+    
+    CGPoint cgp;
+    
+    if ( ! CGDisplayIsCaptured (display_id) ) { /* not captured => not fullscreen => local coord */
+    
+        int height;
+        
+        QZ_PrivateSDLToCocoa (this, p);
+        QZ_PrivateLocalToGlobal (this, p);
+        
+        height = CGDisplayPixelsHigh (display_id);
+        p->y = height - p->y;
+    }
+    
+    cgp.x = p->x;
+    cgp.y = p->y;
+    
+    return cgp;
+}
+
+/* Convert window server (CoreGraphics) coordinate to SDL coordinate */
+static void QZ_PrivateCGToSDL (_THIS, NSPoint *p) {
+            
+    if ( ! CGDisplayIsCaptured (display_id) ) { /* not captured => not fullscreen => local coord */
+    
+        int height;
+
+        /* Convert CG Global to Cocoa Global */
+        height = CGDisplayPixelsHigh (display_id);
+        p->y = height - p->y;
+
+        QZ_PrivateGlobalToLocal (this, p);
+        QZ_PrivateCocoaToSDL (this, p);
     }
 }
 
-static void QZ_WarpWMCursor     (_THIS, Uint16 x, Uint16 y) {
+static void  QZ_PrivateWarpCursor (_THIS, int x, int y) {
+    
+    NSPoint p;
+    CGPoint cgp;
     
+    p = NSMakePoint (x, y);
+    cgp = QZ_PrivateSDLToCG (this, &p);   
+    CGDisplayMoveCursorToPoint (display_id, cgp);
+    warp_ticks = SDL_GetTicks();
+    warp_flag = 1;
+}
+
+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);
+    QZ_PrivateWarpCursor (this, x, y);
 }
 
 static void QZ_MoveWMCursor     (_THIS, int x, int y) { }
@@ -199,6 +271,17 @@
         return 0;
     }
 }
+static int  QZ_IconifyWindow (_THIS) { 
+
+    if ( ! [ qz_window isMiniaturized ] ) {
+        [ qz_window miniaturize:nil ];
+        return 1;
+    }
+    else {
+        SDL_SetError ("Quartz window already iconified");
+        return 0;
+    }
+}
 
 /*
 static int  QZ_GetWMInfo  (_THIS, SDL_SysWMinfo *info) { 
@@ -221,6 +304,7 @@
             currentGrabMode = SDL_GRAB_ON;
             break;
         case SDL_GRAB_FULLSCREEN:
+            
             break;
     }
         
--- a/src/video/quartz/SDL_QuartzWindow.m	Tue Jan 22 18:28:35 2002 +0000
+++ b/src/video/quartz/SDL_QuartzWindow.m	Tue Jan 22 18:46:28 2002 +0000
@@ -7,17 +7,74 @@
 - (void)display;
 @end
 
+/**
+ * Function to set the opacity of window's pixels to 100% 
+ * The opacity is only used by the window server code that does the minimize effect
+ **/
+static void QZ_SetPortAlphaOpaque (CGrafPtr port, Uint32 noTitleBar) {
+    
+    Uint32 *pixels;
+    Uint32  rowPixels;
+    Uint32  width, height;
+    Uint32  bpp;
+    PixMapHandle pixMap;
+    Rect bounds;
+    int i, j;
+    
+    pixMap = GetPortPixMap ( port );
+    bpp = GetPixDepth ( pixMap );
+    
+    if (bpp == 32) {
+    
+        GetPortBounds ( port, &bounds );
+        width = bounds.right - bounds.left;
+        height = bounds.bottom - bounds.top;
+        
+        LockPortBits (port);
+        
+        pixels = (Uint32*) GetPixBaseAddr ( pixMap );
+        rowPixels = GetPixRowBytes ( pixMap ) / 4;
+        
+        if (! noTitleBar) {
+        
+            /* offset for title bar */
+            pixels += rowPixels * 22;
+        }
+            
+        for (i = 0; i < height; i++)
+            for (j = 0; j < width; j++) {
+        
+                pixels[ (i * rowPixels) + j ] |= 0xFF000000;
+            }
+            
+        UnlockPortBits (port);
+    }
+}
+
 @implementation SDL_QuartzWindow
 
-/* These methods should be rewritten to fix the miniaturize bug */
+/* override these methods to fix the miniaturize animation/dock icon bug */
 - (void)miniaturize:(id)sender
 {
+    
+    if (SDL_VideoSurface->flags & SDL_OPENGL) {
+    
+        /* Grab framebuffer and put into NSImage */
+        /* [ qz_window setMiniwindowImage:image ]; */
+    }
+    else {
+        
+        QZ_SetPortAlphaOpaque ([ [ self contentView ] qdPort ], 
+                               [ self styleMask ] & NSBorderlessWindowMask);
+    }
+    
     [ super miniaturize:sender ];
 }
 
+/* this routine fires *after* deminiaturizing, so it might be useless to us */
 - (void)deminiaturize:(id)sender
 {
-    [ super deminiaturize:sender ];
+   [ super deminiaturize:sender ];
 }
 
 - (void)display
@@ -38,4 +95,14 @@
     SDL_PrivateQuit();
     return NO;
 }
+
 @end
+
+/* empty class; probably could be used to fix bugs in the future */
+@interface SDL_QuartzWindowView : NSQuickDrawView
+{}
+@end
+
+@implementation SDL_QuartzWindowView
+
+@end
\ No newline at end of file