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 @@
Sam Lantinga
slouken@libsdl.org
*/
#include <sys/time.h>
#include "SDL_QuartzKeys.h"
......@@ -305,7 +306,13 @@ static void QZ_DoDeactivate (_THIS) {
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 @@ static void QZ_PumpEvents (_THIS)
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 @@ static void QZ_PumpEvents (_THIS)
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 @@ static void QZ_PumpEvents (_THIS)
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 @@ static void QZ_PumpEvents (_THIS)
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 @@ static void QZ_PumpEvents (_THIS)
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 @@ static void QZ_PumpEvents (_THIS)
case NSFlagsChanged:
QZ_DoModifiers( [ event modifierFlags ] );
break;
/* case NSMouseEntered: break; */
/* case NSMouseExited: break; */
case NSAppKitDefined:
switch ( [ event subtype ] ) {
case NSApplicationActivatedEventType:
......@@ -451,12 +489,17 @@ static void QZ_PumpEvents (_THIS)
/* 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 ];
}
......@@ -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 <OpenGL/OpenGL.h>
#include <Cocoa/Cocoa.h>
#include <OpenGL/OpenGL.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 @@ typedef struct SDL_PrivateVideoData {
#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 void QZ_GL_SwapBuffers (_THIS);
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 void QZ_SetIcon (_THIS, SDL_Surface *icon, Uint8 *mask);
static int QZ_IconifyWindow (_THIS);
static SDL_GrabMode QZ_GrabInput (_THIS, SDL_GrabMode grab_mode);
/*static int QZ_GetWMInfo (_THIS, SDL_SysWMinfo *info);*/
This diff is collapsed.
......@@ -87,40 +87,112 @@ static int QZ_ShowWMCursor (_THIS, WMcursor *cursor) {
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.
**/
CGPoint p;
/* 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) {
int height;
/* We require absolute screen coordiates for our warp */
p.x = x;
p.y = h - y;
if ( fullscreen )
/* Already absolute coordinates */
CGDisplayMoveCursorToPoint(display_id, p);
if ( CGDisplayIsCaptured (display_id) ) { /* capture signals fullscreen */
height = CGDisplayPixelsHigh (display_id);
}
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 = NSHeight ( [ qz_window frame ] );
if ( [ qz_window styleMask ] & NSTitledWindowMask ) {
height -= 22;
}
}
p->y = height - p->y;
}
static void QZ_WarpWMCursor (_THIS, Uint16 x, Uint16 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) {
/* 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 @@ static int QZ_IconifyWindow (_THIS) {
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 @@ static SDL_GrabMode QZ_GrabInput (_THIS, SDL_GrabMode grab_mode) {
currentGrabMode = SDL_GRAB_ON;
break;
case SDL_GRAB_FULLSCREEN:
break;
}
......
......@@ -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
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