Commit 06db61e1 authored by Sam Lantinga's avatar Sam Lantinga

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.

--HG--
extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/trunk%40273
parent d8881664
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
Sam Lantinga Sam Lantinga
slouken@libsdl.org slouken@libsdl.org
*/ */
#include <sys/time.h>
#include "SDL_QuartzKeys.h" #include "SDL_QuartzKeys.h"
...@@ -305,6 +306,12 @@ static void QZ_DoDeactivate (_THIS) { ...@@ -305,6 +306,12 @@ static void QZ_DoDeactivate (_THIS) {
static void QZ_PumpEvents (_THIS) static void QZ_PumpEvents (_THIS)
{ {
static NSPoint lastMouse;
NSPoint mouse, saveMouse;
Point qdMouse;
CGMouseDelta dx, dy;
NSDate *distantPast; NSDate *distantPast;
NSEvent *event; NSEvent *event;
NSRect winRect; NSRect winRect;
...@@ -314,10 +321,36 @@ static void QZ_PumpEvents (_THIS) ...@@ -314,10 +321,36 @@ static void QZ_PumpEvents (_THIS)
pool = [ [ NSAutoreleasePool alloc ] init ]; pool = [ [ NSAutoreleasePool alloc ] init ];
distantPast = [ NSDate distantPast ]; 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, titleBarRect = NSMakeRect ( 0, SDL_VideoSurface->h, SDL_VideoSurface->w,
SDL_VideoSurface->h + 22 ); 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 { do {
/* Poll for an event. This will not block */ /* Poll for an event. This will not block */
...@@ -343,7 +376,7 @@ static void QZ_PumpEvents (_THIS) ...@@ -343,7 +376,7 @@ static void QZ_PumpEvents (_THIS)
#define DO_MOUSE_UP(button, sendToWindow) do { \ #define DO_MOUSE_UP(button, sendToWindow) do { \
if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN) || \ if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN) || \
!NSPointInRect([event locationInWindow], titleBarRect) )\ !NSPointInRect([event locationInWindow], titleBarRect) ) \
SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0); \ SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0); \
[ NSApp sendEvent:event ]; \ [ NSApp sendEvent:event ]; \
} while(0) } while(0)
...@@ -365,7 +398,7 @@ static void QZ_PumpEvents (_THIS) ...@@ -365,7 +398,7 @@ static void QZ_PumpEvents (_THIS)
DO_MOUSE_DOWN (1, 1); DO_MOUSE_DOWN (1, 1);
} }
break; 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 NSRightMouseDown: DO_MOUSE_DOWN (3, 0); break;
case NSLeftMouseUp: case NSLeftMouseUp:
...@@ -377,7 +410,7 @@ static void QZ_PumpEvents (_THIS) ...@@ -377,7 +410,7 @@ static void QZ_PumpEvents (_THIS)
DO_MOUSE_UP (1, 1); DO_MOUSE_UP (1, 1);
} }
break; 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 NSRightMouseUp: DO_MOUSE_UP (3, 0); break;
case NSSystemDefined: case NSSystemDefined:
//if ([event subtype] == 7) { //if ([event subtype] == 7) {
...@@ -389,30 +422,37 @@ static void QZ_PumpEvents (_THIS) ...@@ -389,30 +422,37 @@ static void QZ_PumpEvents (_THIS)
case NSRightMouseDragged: case NSRightMouseDragged:
case 27: case 27:
case NSMouseMoved: case NSMouseMoved:
if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN)
|| NSPointInRect([event locationInWindow], winRect) ) if (currentGrabMode == SDL_GRAB_ON) {
{
static int moves = 0; /**
NSPoint p; * If input is grabbed, we'll wing it and try to send some mouse
* moved events with CGGetLastMouseDelta(). Not optimal, but better
if ( SDL_VideoSurface->flags & SDL_FULLSCREEN ) { * than nothing.
p = [ NSEvent mouseLocation ]; **/
p.y = [[NSScreen mainScreen] frame].size.height - p.y; CGMouseDelta dx1, dy1;
} else { CGGetLastMouseDelta (&dx1, &dy1);
p = [ event locationInWindow ]; dx += dx1;
p.y = SDL_VideoSurface->h - p.y; dy += dy1;
} }
else if (warp_flag) {
if ( (moves % 10) == 0 ) { Uint32 ticks;
SDL_PrivateMouseMotion (0, 0, p.x, p.y);
ticks = SDL_GetTicks();
if (ticks - warp_ticks < 150) {
CGMouseDelta dx1, dy1;
CGGetLastMouseDelta (&dx1, &dy1);
dx += dx1;
dy += dy1;
} }
else { else {
CGMouseDelta dx, dy;
CGGetLastMouseDelta (&dx, &dy); warp_flag = 0;
SDL_PrivateMouseMotion (0, 1, dx, dy);
} }
moves++;
} }
break; break;
case NSScrollWheel: case NSScrollWheel:
{ {
...@@ -435,8 +475,6 @@ static void QZ_PumpEvents (_THIS) ...@@ -435,8 +475,6 @@ static void QZ_PumpEvents (_THIS)
case NSFlagsChanged: case NSFlagsChanged:
QZ_DoModifiers( [ event modifierFlags ] ); QZ_DoModifiers( [ event modifierFlags ] );
break; break;
/* case NSMouseEntered: break; */
/* case NSMouseExited: break; */
case NSAppKitDefined: case NSAppKitDefined:
switch ( [ event subtype ] ) { switch ( [ event subtype ] ) {
case NSApplicationActivatedEventType: case NSApplicationActivatedEventType:
...@@ -451,12 +489,17 @@ static void QZ_PumpEvents (_THIS) ...@@ -451,12 +489,17 @@ static void QZ_PumpEvents (_THIS)
/* case NSApplicationDefined: break; */ /* case NSApplicationDefined: break; */
/* case NSPeriodic: break; */ /* case NSPeriodic: break; */
/* case NSCursorUpdate: break; */ /* case NSCursorUpdate: break; */
default: default:
[ NSApp sendEvent:event ]; [ NSApp sendEvent:event ];
} }
} }
} while (event != nil); } while (event != nil);
/* check for accumulated mouse events */
if (dx != 0 || dy != 0)
SDL_PrivateMouseMotion (0, 1, dx, dy);
[ pool release ]; [ pool release ];
} }
...@@ -34,25 +34,28 @@ ...@@ -34,25 +34,28 @@
- Multiple monitor support (currently only main display) - Multiple monitor support (currently only main display)
- Accelerated blitting support - Accelerated blitting support
- Set the window icon (dock icon when API is available) - 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: Problems:
- OGL not working in full screen with software renderer - OGL not working in full screen with software renderer
- SetColors sets palette correctly but clears framebuffer - SetColors sets palette correctly but clears framebuffer
- Crash in CG after several mode switches - Crash in CG after several mode switches
- Retained windows don't draw their title bar quite right (OS Bug) - Retained windows don't draw their title bar quite right (OS Bug) (not using retained windows)
- Should I do depth switching for windowed modes? - No, not usually. - Cursor in 8 bit modes is screwy (might just be Radeon PCI bug)
- Launch times are slow, maybe prebinding will help - Warping cursor delays mouse events for a fraction of a second,
- Direct framebuffer access has some artifacts, maybe a driver issue there is a hack around this that helps a bit
- Cursor in 8 bit modes is screwy
*/ */
#include <ApplicationServices/ApplicationServices.h>
#include <OpenGL/OpenGL.h>
#include <Cocoa/Cocoa.h> #include <Cocoa/Cocoa.h>
#include <OpenGL/OpenGL.h>
#include <Carbon/Carbon.h> #include <Carbon/Carbon.h>
#include "SDL_video.h" #include "SDL_video.h"
#include "SDL_error.h" #include "SDL_error.h"
#include "SDL_timer.h"
#include "SDL_syswm.h" #include "SDL_syswm.h"
#include "SDL_sysvideo.h" #include "SDL_sysvideo.h"
#include "SDL_pixels_c.h" #include "SDL_pixels_c.h"
...@@ -71,21 +74,34 @@ ...@@ -71,21 +74,34 @@
} }
@end @end
typedef struct SDL_PrivateVideoData { /* 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 {
CGDirectDisplayID display; /* 0 == main display */ CGGammaValue red[QZ_GAMMA_TABLE_SIZE];
CFDictionaryRef mode; CGGammaValue green[QZ_GAMMA_TABLE_SIZE];
CFDictionaryRef save_mode; CGGammaValue blue[QZ_GAMMA_TABLE_SIZE];
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 */ } SDL_QuartzGammaTable;
NSWindow *window;
NSQuickDrawView *view; /* Main driver structure to store required state information */
typedef struct SDL_PrivateVideoData {
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 ; } SDL_PrivateVideoData ;
...@@ -95,21 +111,68 @@ typedef struct SDL_PrivateVideoData { ...@@ -95,21 +111,68 @@ typedef struct SDL_PrivateVideoData {
#define save_mode (this->hidden->save_mode) #define save_mode (this->hidden->save_mode)
#define mode_list (this->hidden->mode_list) #define mode_list (this->hidden->mode_list)
#define palette (this->hidden->palette) #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 gl_context (this->hidden->gl_context)
#define device_width (this->hidden->width) #define device_width (this->hidden->width)
#define device_height (this->hidden->height) #define device_height (this->hidden->height)
#define device_bpp (this->hidden->bpp) #define device_bpp (this->hidden->bpp)
#define mode_flags (this->hidden->flags) #define mode_flags (this->hidden->flags)
#define video_set (this->hidden->video_is_set)
#define qz_window (this->hidden->window) #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 */ typedef CGError CGSError;
int CGSDisplayHWFill (CGDirectDisplayID id, unsigned int x, unsigned int y, 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); 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 */ /* Bootstrap functions */
static int QZ_Available (); static int QZ_Available ();
...@@ -156,7 +219,7 @@ static void QZ_GL_SwapBuffers (_THIS); ...@@ -156,7 +219,7 @@ static void QZ_GL_SwapBuffers (_THIS);
static int QZ_GL_LoadLibrary (_THIS, const char *location); static int QZ_GL_LoadLibrary (_THIS, const char *location);
/* Private function to warp the cursor (used internally) */ /* 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 */ /* Cursor and Mouse functions */
static void QZ_FreeWMCursor (_THIS, WMcursor *cursor); static void QZ_FreeWMCursor (_THIS, WMcursor *cursor);
...@@ -177,3 +240,4 @@ static void QZ_SetIcon (_THIS, SDL_Surface *icon, Uint8 *mask); ...@@ -177,3 +240,4 @@ static void QZ_SetIcon (_THIS, SDL_Surface *icon, Uint8 *mask);
static int QZ_IconifyWindow (_THIS); static int QZ_IconifyWindow (_THIS);
static SDL_GrabMode QZ_GrabInput (_THIS, SDL_GrabMode grab_mode); static SDL_GrabMode QZ_GrabInput (_THIS, SDL_GrabMode grab_mode);
/*static int QZ_GetWMInfo (_THIS, SDL_SysWMinfo *info);*/ /*static int QZ_GetWMInfo (_THIS, SDL_SysWMinfo *info);*/
...@@ -32,9 +32,10 @@ static char QZ_Error[255]; /* Global error buffer to temporarily store more info ...@@ -32,9 +32,10 @@ static char QZ_Error[255]; /* Global error buffer to temporarily store more info
#include "SDL_QuartzEvents.m" #include "SDL_QuartzEvents.m"
#include "SDL_QuartzWindow.m" #include "SDL_QuartzWindow.m"
/* Bootstrap binding, enables entry point into the driver */ /* Bootstrap binding, enables entry point into the driver */
VideoBootStrap QZ_bootstrap = { VideoBootStrap QZ_bootstrap = {
"Quartz", "MacOS X CoreGraphics", QZ_Available, QZ_CreateDevice "Quartz", "Mac OS X CoreGraphics", QZ_Available, QZ_CreateDevice
}; };
/* Bootstrap functions */ /* Bootstrap functions */
...@@ -44,7 +45,7 @@ static int QZ_Available () { ...@@ -44,7 +45,7 @@ static int QZ_Available () {
static SDL_VideoDevice* QZ_CreateDevice (int device_index) { static SDL_VideoDevice* QZ_CreateDevice (int device_index) {
#pragma unused (device_index) #pragma unused (device_index)
SDL_VideoDevice *device; SDL_VideoDevice *device;
SDL_PrivateVideoData *hidden; SDL_PrivateVideoData *hidden;
...@@ -135,7 +136,7 @@ static int QZ_VideoInit (_THIS, SDL_PixelFormat *video_format) { ...@@ -135,7 +136,7 @@ static int QZ_VideoInit (_THIS, SDL_PixelFormat *video_format) {
static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format, Uint32 flags) { static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format, Uint32 flags) {
CFIndex num_modes = CFArrayGetCount (mode_list); CFIndex num_modes;
CFIndex i; CFIndex i;
static SDL_Rect **list = NULL; static SDL_Rect **list = NULL;
...@@ -157,6 +158,8 @@ static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format, Uint32 flags) { ...@@ -157,6 +158,8 @@ static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format, Uint32 flags) {
list = NULL; list = NULL;
} }
num_modes = CFArrayGetCount (mode_list);
/* Build list of modes with the requested bpp */ /* Build list of modes with the requested bpp */
for (i = 0; i < num_modes; i++) { for (i = 0; i < num_modes; i++) {
...@@ -201,15 +204,17 @@ static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format, Uint32 flags) { ...@@ -201,15 +204,17 @@ static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format, Uint32 flags) {
list_size++; list_size++;
if ( list == NULL) if (list == NULL)
list = (SDL_Rect**) malloc (sizeof(*list) * list_size+1); list = (SDL_Rect**) malloc (sizeof(*list) * (list_size+1) );
else 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)); rect = (SDL_Rect*) malloc (sizeof(**list));
if (list == NULL || rect == NULL) if (list == NULL || rect == NULL) {
SDL_OutOfMemory (); SDL_OutOfMemory ();
return NULL;
}
rect->w = width; rect->w = width;
rect->h = height; rect->h = height;
...@@ -241,6 +246,92 @@ static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format, Uint32 flags) { ...@@ -241,6 +246,92 @@ static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format, Uint32 flags) {
return list; 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) { static void QZ_UnsetVideoMode (_THIS) {
/* Reset values that may change between switches */ /* Reset values that may change between switches */
...@@ -248,36 +339,53 @@ static void QZ_UnsetVideoMode (_THIS) { ...@@ -248,36 +339,53 @@ static void QZ_UnsetVideoMode (_THIS) {
this->FillHWRect = NULL; this->FillHWRect = NULL;
this->UpdateRects = NULL; this->UpdateRects = NULL;
/* Restore gamma settings */ /* Release fullscreen resources */
CGDisplayRestoreColorSyncSettings ();
/* Restore original screen resolution */
if ( mode_flags & SDL_FULLSCREEN ) { 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) if (mode_flags & SDL_OPENGL)
CGLSetFullScreen(NULL); CGLSetFullScreen(NULL);
/* Restore original screen resolution/bpp */
CGDisplaySwitchToMode (display_id, save_mode); CGDisplaySwitchToMode (display_id, save_mode);
CGDisplayRelease (display_id); CGDisplayRelease (display_id);
ShowMenuBar ();
if (! gamma_error)
QZ_FadeGammaIn (this, &gamma_table);
} }
/* Release window mode data structures */ /* Release window mode resources */
else { else {
if ( (mode_flags & SDL_OPENGL) == 0 ) { if ( (mode_flags & SDL_OPENGL) == 0 ) {
UnlockPortBits ( [ windowView qdPort ] ); UnlockPortBits ( [ window_view qdPort ] );
[ windowView release ]; [ window_view release ];
} }
[ qz_window setContentView:nil ]; [ qz_window setContentView:nil ];
[ qz_window setDelegate:nil ]; [ qz_window setDelegate:nil ];
[ qz_window close ]; [ 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) */ /* Set pixels to null (so other code doesn't try to free it) */
if (this->screen != NULL) if (this->screen != NULL)
this->screen->pixels = 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 */ /* Ensure the cursor will be visible and working when we quit */
CGDisplayShowCursor (display_id); CGDisplayShowCursor (display_id);
CGAssociateMouseAndMouseCursorPosition (1); CGAssociateMouseAndMouseCursorPosition (1);
...@@ -289,6 +397,8 @@ static void QZ_UnsetVideoMode (_THIS) { ...@@ -289,6 +397,8 @@ static void QZ_UnsetVideoMode (_THIS) {
static SDL_Surface* QZ_SetVideoFullScreen (_THIS, SDL_Surface *current, int width, static SDL_Surface* QZ_SetVideoFullScreen (_THIS, SDL_Surface *current, int width,
int height, int bpp, Uint32 flags) { int height, int bpp, Uint32 flags) {
int exact_match; int exact_match;
int gamma_error;
SDL_QuartzGammaTable gamma_table;
/* See if requested mode exists */ /* See if requested mode exists */
mode = CGDisplayBestModeForParameters (display_id, bpp, width, mode = CGDisplayBestModeForParameters (display_id, bpp, width,
...@@ -301,34 +411,24 @@ static SDL_Surface* QZ_SetVideoFullScreen (_THIS, SDL_Surface *current, int widt ...@@ -301,34 +411,24 @@ static SDL_Surface* QZ_SetVideoFullScreen (_THIS, SDL_Surface *current, int widt
goto ERR_NO_MATCH; 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) */ /* Put up the blanking window (a window above all other windows) */
if ( CGDisplayNoErr != CGDisplayCapture (display_id) ) { if ( CGDisplayNoErr != CGDisplayCapture (display_id) ) {
SDL_SetError ("Failed capturing display"); SDL_SetError ("Failed capturing display");
goto ERR_NO_CAPTURE; goto ERR_NO_CAPTURE;
} }
/* Do the physical switch */ /* Do the physical switch */
if ( CGDisplayNoErr != CGDisplaySwitchToMode (display_id, mode) ) { if ( CGDisplayNoErr != CGDisplaySwitchToMode (display_id, mode) ) {
SDL_SetError ("Failed switching display resolution"); SDL_SetError ("Failed switching display resolution");
goto ERR_NO_SWITCH; 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->pixels = (Uint32*) CGDisplayBaseAddress (display_id);
current->pitch = CGDisplayBytesPerRow (display_id); current->pitch = CGDisplayBytesPerRow (display_id);
#endif
current->flags = 0; current->flags = 0;
current->w = width; current->w = width;
...@@ -354,7 +454,7 @@ static SDL_Surface* QZ_SetVideoFullScreen (_THIS, SDL_Surface *current, int widt ...@@ -354,7 +454,7 @@ static SDL_Surface* QZ_SetVideoFullScreen (_THIS, SDL_Surface *current, int widt
CGLContextObj ctx; CGLContextObj ctx;
if ( ! QZ_SetupOpenGL (this, bpp, flags) ) { if ( ! QZ_SetupOpenGL (this, bpp, flags) ) {
return NULL; goto ERR_NO_GL;
} }
ctx = [ gl_context cglContext ]; ctx = [ gl_context cglContext ];
...@@ -368,21 +468,29 @@ static SDL_Surface* QZ_SetVideoFullScreen (_THIS, SDL_Surface *current, int widt ...@@ -368,21 +468,29 @@ static SDL_Surface* QZ_SetVideoFullScreen (_THIS, SDL_Surface *current, int widt
[ gl_context makeCurrentContext]; [ gl_context makeCurrentContext];
glClear (GL_COLOR_BUFFER_BIT);
[ gl_context flushBuffer ];
current->flags |= SDL_OPENGL; current->flags |= SDL_OPENGL;
} }
/* If we don't hide menu bar, it will get events and interrupt the program */ /* If we don't hide menu bar, it will get events and interrupt the program */
HideMenuBar (); HideMenuBar ();
/* Fade the display to original gamma */
if (! gamma_error )
QZ_FadeGammaIn (this, &gamma_table);
/* Save the flags to ensure correct tear-down */ /* Save the flags to ensure correct tear-down */
mode_flags = current->flags; mode_flags = current->flags;
return current; 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_GL: CGDisplaySwitchToMode (display_id, save_mode);
ERR_NO_SWITCH: CGDisplayRelease (display_id); 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; ERR_NO_MATCH: return NULL;
} }
...@@ -440,16 +548,17 @@ static SDL_Surface* QZ_SetVideoWindowed (_THIS, SDL_Surface *current, int width, ...@@ -440,16 +548,17 @@ static SDL_Surface* QZ_SetVideoWindowed (_THIS, SDL_Surface *current, int width,
/* For 2D, we set the content view to a NSQuickDrawView */ /* For 2D, we set the content view to a NSQuickDrawView */
else { else {
windowView = [ [ NSQuickDrawView alloc ] init ]; window_view = [ [ SDL_QuartzWindowView alloc ] init ];
[ qz_window setContentView:windowView ]; [ qz_window setContentView:window_view ];
[ qz_window makeKeyAndOrderFront:nil ]; [ qz_window makeKeyAndOrderFront:nil ];
LockPortBits ( [ windowView qdPort ] ); LockPortBits ( [ window_view qdPort ] );
current->pixels = GetPixBaseAddr ( GetPortPixMap ( [ windowView qdPort ] ) ); current->pixels = GetPixBaseAddr ( GetPortPixMap ( [ window_view qdPort ] ) );
current->pitch = GetPixRowBytes ( GetPortPixMap ( [ windowView qdPort ] ) ); current->pitch = GetPixRowBytes ( GetPortPixMap ( [ window_view qdPort ] ) );
current->flags |= SDL_SWSURFACE; current->flags |= SDL_SWSURFACE;
current->flags |= SDL_PREALLOC; current->flags |= SDL_PREALLOC;
if ( flags & SDL_NOFRAME ) if ( flags & SDL_NOFRAME )
current->flags |= SDL_NOFRAME; current->flags |= SDL_NOFRAME;
if ( flags & SDL_RESIZABLE ) if ( flags & SDL_RESIZABLE )
...@@ -462,6 +571,10 @@ static SDL_Surface* QZ_SetVideoWindowed (_THIS, SDL_Surface *current, int width, ...@@ -462,6 +571,10 @@ static SDL_Surface* QZ_SetVideoWindowed (_THIS, SDL_Surface *current, int width,
this->UpdateRects = QZ_UpdateRects; this->UpdateRects = QZ_UpdateRects;
} }
/* Save flags to ensure correct teardown */
mode_flags = current->flags;
return current; return current;
} }
...@@ -482,7 +595,7 @@ static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current, int width, ...@@ -482,7 +595,7 @@ static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current, int width,
/* Setup windowed video */ /* Setup windowed video */
else { else {
/* Force bpp to the device's bpp */ /* Force bpp to the device's bpp */
bpp = current->format->BitsPerPixel; bpp = device_bpp;
current = QZ_SetVideoWindowed (this, current, width, height, bpp, flags); current = QZ_SetVideoWindowed (this, current, width, height, bpp, flags);
if (current == NULL) if (current == NULL)
return NULL; return NULL;
...@@ -520,10 +633,7 @@ static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current, int width, ...@@ -520,10 +633,7 @@ static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current, int width,
} }
} }
/* Warp mouse to origin in order to get passive mouse motion events started correctly */ /* Signal successful completion (used internally) */
QZ_PrivateWarpCursor (this, current->flags & SDL_FULLSCREEN, height, 0, 0);
/* Signal successful completion */
video_set = SDL_TRUE; video_set = SDL_TRUE;
return current; return current;
...@@ -561,12 +671,293 @@ static void QZ_DirectUpdate (_THIS, int num_rects, SDL_Rect *rects) { ...@@ -561,12 +671,293 @@ static void QZ_DirectUpdate (_THIS, int num_rects, SDL_Rect *rects) {
#pragma unused(this,num_rects,rects) #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) { static void QZ_UpdateRects (_THIS, int numRects, SDL_Rect *rects) {
if (SDL_VideoSurface->flags & SDL_OPENGLBLIT) { if (SDL_VideoSurface->flags & SDL_OPENGLBLIT) {
QZ_GL_SwapBuffers (this); 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 { else {
/* Use QDFlushPortBuffer() to flush content to display */
int i; int i;
RgnHandle dirty = NewRgn (); RgnHandle dirty = NewRgn ();
RgnHandle temp = NewRgn (); RgnHandle temp = NewRgn ();
...@@ -582,7 +973,7 @@ static void QZ_UpdateRects (_THIS, int numRects, SDL_Rect *rects) { ...@@ -582,7 +973,7 @@ static void QZ_UpdateRects (_THIS, int numRects, SDL_Rect *rects) {
} }
/* Flush the dirty region */ /* Flush the dirty region */
QDFlushPortBuffer ( [ windowView qdPort ], dirty ); QDFlushPortBuffer ( [ window_view qdPort ], dirty );
DisposeRgn (dirty); DisposeRgn (dirty);
DisposeRgn (temp); DisposeRgn (temp);
} }
...@@ -597,6 +988,7 @@ static void QZ_VideoQuit (_THIS) { ...@@ -597,6 +988,7 @@ static void QZ_VideoQuit (_THIS) {
static int QZ_FillHWRect (_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color) { 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); CGSDisplayHWFill (display_id, rect->x, rect->y, rect->w, rect->h, color);
return 0; return 0;
} }
...@@ -606,6 +998,7 @@ static int QZ_LockHWSurface(_THIS, SDL_Surface *surface) { ...@@ -606,6 +998,7 @@ static int QZ_LockHWSurface(_THIS, SDL_Surface *surface) {
} }
static void QZ_UnlockHWSurface(_THIS, SDL_Surface *surface) { static void QZ_UnlockHWSurface(_THIS, SDL_Surface *surface) {
} }
static void QZ_FreeHWSurface (_THIS, SDL_Surface *surface) { static void QZ_FreeHWSurface (_THIS, SDL_Surface *surface) {
...@@ -622,23 +1015,42 @@ static int QZ_SetGamma (_THIS, float red, float green, float blue) { ...@@ -622,23 +1015,42 @@ static int QZ_SetGamma (_THIS, float red, float green, float blue) {
const CGGammaValue min = 0.0, max = 1.0; const CGGammaValue min = 0.0, max = 1.0;
if ( CGDisplayNoErr != CGSetDisplayTransferByFormula if (red == 0.0)
(display_id, min, max, red, min, max, green, min, max, blue) ) red = FLT_MAX;
return -1; 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) ) {
return 0; return 0;
}
else {
return -1;
}
} }
static int QZ_GetGamma (_THIS, float *red, float *green, float *blue) { static int QZ_GetGamma (_THIS, float *red, float *green, float *blue) {
CGGammaValue dummy; CGGammaValue dummy;
if ( CGDisplayNoErr != CGGetDisplayTransferByFormula if ( CGDisplayNoErr == CGGetDisplayTransferByFormula
(display_id, &dummy, &dummy, red, (display_id, &dummy, &dummy, red,
&dummy, &dummy, green, &dummy, &dummy, blue) ) &dummy, &dummy, green, &dummy, &dummy, blue) )
return -1;
return 0; return 0;
else
return -1;
} }
static int QZ_SetGammaRamp (_THIS, Uint16 *ramp) { static int QZ_SetGammaRamp (_THIS, Uint16 *ramp) {
...@@ -660,11 +1072,11 @@ static int QZ_SetGammaRamp (_THIS, Uint16 *ramp) { ...@@ -660,11 +1072,11 @@ static int QZ_SetGammaRamp (_THIS, Uint16 *ramp) {
for (i=512; i < 768; i++) for (i=512; i < 768; i++)
blueTable[i % 256] = ramp[i] / 65535.0; blueTable[i % 256] = ramp[i] / 65535.0;
if ( CGDisplayNoErr != CGSetDisplayTransferByTable if ( CGDisplayNoErr == CGSetDisplayTransferByTable
(display_id, tableSize, redTable, greenTable, blueTable) ) (display_id, tableSize, redTable, greenTable, blueTable) )
return -1;
return 0; return 0;
else
return -1;
} }
static int QZ_GetGammaRamp (_THIS, Uint16 *ramp) { static int QZ_GetGammaRamp (_THIS, Uint16 *ramp) {
...@@ -695,7 +1107,8 @@ static int QZ_GetGammaRamp (_THIS, Uint16 *ramp) { ...@@ -695,7 +1107,8 @@ static int QZ_GetGammaRamp (_THIS, Uint16 *ramp) {
return 0; return 0;
} }
/* OpenGL helper functions */ /* OpenGL helper functions (used internally) */
static int QZ_SetupOpenGL (_THIS, int bpp, Uint32 flags) { static int QZ_SetupOpenGL (_THIS, int bpp, Uint32 flags) {
NSOpenGLPixelFormatAttribute attr[32]; NSOpenGLPixelFormatAttribute attr[32];
...@@ -761,6 +1174,7 @@ static void QZ_TearDownOpenGL (_THIS) { ...@@ -761,6 +1174,7 @@ static void QZ_TearDownOpenGL (_THIS) {
[ gl_context release ]; [ gl_context release ];
} }
/* SDL OpenGL functions */ /* SDL OpenGL functions */
static int QZ_GL_LoadLibrary (_THIS, const char *location) { static int QZ_GL_LoadLibrary (_THIS, const char *location) {
...@@ -805,6 +1219,7 @@ static int QZ_GL_GetAttribute (_THIS, SDL_GLattr attrib, int* value) { ...@@ -805,6 +1219,7 @@ static int QZ_GL_GetAttribute (_THIS, SDL_GLattr attrib, int* value) {
CGLGetParameter (ctx, param, (long*)value); CGLGetParameter (ctx, param, (long*)value);
*/ */
*value = -1; *value = -1;
return -1; return -1;
} }
...@@ -817,3 +1232,5 @@ static int QZ_GL_MakeCurrent (_THIS) { ...@@ -817,3 +1232,5 @@ static int QZ_GL_MakeCurrent (_THIS) {
static void QZ_GL_SwapBuffers (_THIS) { static void QZ_GL_SwapBuffers (_THIS) {
[ gl_context flushBuffer ]; [ gl_context flushBuffer ];
} }
...@@ -87,26 +87,102 @@ static int QZ_ShowWMCursor (_THIS, WMcursor *cursor) { ...@@ -87,26 +87,102 @@ static int QZ_ShowWMCursor (_THIS, WMcursor *cursor) {
return 1; 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) {
*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) {
CGPoint p; int height;
/* We require absolute screen coordiates for our warp */ if ( CGDisplayIsCaptured (display_id) ) { /* capture signals fullscreen */
p.x = x;
p.y = h - y;
if ( fullscreen ) height = CGDisplayPixelsHigh (display_id);
/* Already absolute coordinates */ }
CGDisplayMoveCursorToPoint(display_id, p);
else { else {
/* Convert to absolute screen coordinates */
NSPoint base, screen; height = NSHeight ( [ qz_window frame ] );
base = NSMakePoint (p.x, p.y); if ( [ qz_window styleMask ] & NSTitledWindowMask ) {
screen = [ qz_window convertBaseToScreen:base ];
p.x = screen.x; height -= 22;
p.y = device_height - screen.y; }
CGDisplayMoveCursorToPoint (display_id, p); }
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_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) { static void QZ_WarpWMCursor (_THIS, Uint16 x, Uint16 y) {
...@@ -116,11 +192,7 @@ static void QZ_WarpWMCursor (_THIS, Uint16 x, Uint16 y) { ...@@ -116,11 +192,7 @@ static void QZ_WarpWMCursor (_THIS, Uint16 x, Uint16 y) {
return; return;
/* Do the actual warp */ /* Do the actual warp */
QZ_PrivateWarpCursor (this, SDL_VideoSurface->flags & SDL_FULLSCREEN, QZ_PrivateWarpCursor (this, x, y);
SDL_VideoSurface->h, x, y);
/* Generate mouse moved event */
SDL_PrivateMouseMotion (SDL_RELEASED, 0, x, y);
} }
static void QZ_MoveWMCursor (_THIS, int x, int y) { } static void QZ_MoveWMCursor (_THIS, int x, int y) { }
...@@ -199,6 +271,17 @@ static int QZ_IconifyWindow (_THIS) { ...@@ -199,6 +271,17 @@ static int QZ_IconifyWindow (_THIS) {
return 0; 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) { static int QZ_GetWMInfo (_THIS, SDL_SysWMinfo *info) {
...@@ -221,6 +304,7 @@ static SDL_GrabMode QZ_GrabInput (_THIS, SDL_GrabMode grab_mode) { ...@@ -221,6 +304,7 @@ static SDL_GrabMode QZ_GrabInput (_THIS, SDL_GrabMode grab_mode) {
currentGrabMode = SDL_GRAB_ON; currentGrabMode = SDL_GRAB_ON;
break; break;
case SDL_GRAB_FULLSCREEN: case SDL_GRAB_FULLSCREEN:
break; break;
} }
......
...@@ -7,14 +7,71 @@ ...@@ -7,14 +7,71 @@
- (void)display; - (void)display;
@end @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 @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 - (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 ]; [ super miniaturize:sender ];
} }
/* this routine fires *after* deminiaturizing, so it might be useless to us */
- (void)deminiaturize:(id)sender - (void)deminiaturize:(id)sender
{ {
[ super deminiaturize:sender ]; [ super deminiaturize:sender ];
...@@ -38,4 +95,14 @@ ...@@ -38,4 +95,14 @@
SDL_PrivateQuit(); SDL_PrivateQuit();
return NO; return NO;
} }
@end
/* empty class; probably could be used to fix bugs in the future */
@interface SDL_QuartzWindowView : NSQuickDrawView
{}
@end
@implementation SDL_QuartzWindowView
@end @end
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment