--- 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;
}