From 9aca8cc864bc7081ed251583befef139481273fe Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sun, 10 Aug 2003 07:21:43 +0000 Subject: [PATCH] Date: Sat, 9 Aug 2003 20:14:06 -0400 From: Darrell Walisser Subject: Re: Updated projects? >> Did you get a chance to look at my "Custom Cocoa" demo? I have a few >> minor patches that enable SDL/Cocoa integration, and a project >> template. > > I didn't yet, but go ahead and send me the patches. :) > I updated the patch for current CVS. There are a lot of changes, but I don't think I've broken anything. This patch also improves the behavior of window minimize/deminimize. --- src/video/quartz/SDL_QuartzEvents.m | 5 +- src/video/quartz/SDL_QuartzVideo.m | 59 ++++++++++++++++--- src/video/quartz/SDL_QuartzWM.m | 30 ++++++---- src/video/quartz/SDL_QuartzWindow.m | 89 +++++++++++++++++++++++------ 4 files changed, 146 insertions(+), 37 deletions(-) diff --git a/src/video/quartz/SDL_QuartzEvents.m b/src/video/quartz/SDL_QuartzEvents.m index c27be0218..631299862 100644 --- a/src/video/quartz/SDL_QuartzEvents.m +++ b/src/video/quartz/SDL_QuartzEvents.m @@ -251,6 +251,9 @@ static void QZ_DoKey (_THIS, int state, NSEvent *event) { SDL_PrivateKeyboard (state, &key); } } + + if (getenv ("SDL_ENABLEAPPEVENTS")) + [ NSApp sendEvent:event ]; } static void QZ_DoModifiers (_THIS, unsigned int newMods) { @@ -464,7 +467,7 @@ static void QZ_PumpEvents (_THIS) type = [ event type ]; isForGameWin = (qz_window == [ event window ]); - isInGameWin = (mode_flags & SDL_FULLSCREEN) ? true : NSPointInRect([event locationInWindow], winRect); + isInGameWin = (mode_flags & SDL_FULLSCREEN) ? true : NSPointInRect([event locationInWindow], [ window_view frame ]); switch (type) { case NSLeftMouseDown: if ( getenv("SDL_HAS3BUTTONMOUSE") ) { diff --git a/src/video/quartz/SDL_QuartzVideo.m b/src/video/quartz/SDL_QuartzVideo.m index d3b234c31..faee91116 100644 --- a/src/video/quartz/SDL_QuartzVideo.m +++ b/src/video/quartz/SDL_QuartzVideo.m @@ -396,7 +396,6 @@ static void QZ_UnsetVideoMode (_THIS) { CGDisplaySwitchToMode (display_id, save_mode); CGReleaseAllDisplays (); ShowMenuBar (); - /* Reset the main screen's rectangle See comment in QZ_SetVideoFullscreen for why we do this @@ -580,6 +579,7 @@ other blitting while waiting on the VBL (and hence results in higher framerates) int height, int bpp, Uint32 flags) { unsigned int style; NSRect contentRect; + BOOL isCustom = NO; int center_window = 1; int origin_x, origin_y; @@ -602,7 +602,41 @@ other blitting while waiting on the VBL (and hence results in higher framerates) (mode_flags & SDL_OPENGL) || (flags & SDL_OPENGL) ) QZ_UnsetVideoMode (this); - + + /* Check for user-specified window and view */ + { + char *windowPtrString = getenv ("SDL_NSWindowPointer"); + char *viewPtrString = getenv ("SDL_NSQuickDrawViewPointer"); + + if (windowPtrString && viewPtrString) { + + /* Release any previous window */ + if ( qz_window ) { + [ qz_window release ]; + qz_window = nil; + } + + qz_window = (NSWindow*)atoi(windowPtrString); + window_view = (NSQuickDrawView*)atoi(viewPtrString); + isCustom = YES; + + /* + Retain reference to window because we + might release it in QZ_UnsetVideoMode + */ + [ qz_window retain ]; + + style = [ qz_window styleMask ]; + /* Check resizability */ + if ( style & NSResizableWindowMask ) + current->flags |= SDL_RESIZABLE; + + /* Check frame */ + if ( style & NSBorderlessWindowMask ) + current->flags |= SDL_NOFRAME; + } + } + /* Check if we should recreate the window */ if (qz_window == nil) { @@ -650,8 +684,10 @@ other blitting while waiting on the VBL (and hence results in higher framerates) /* We already have a window, just change its size */ else { - [ qz_window setContentSize:contentRect.size ]; - current->flags |= (SDL_NOFRAME|SDL_RESIZABLE) & mode_flags; + if (!isCustom) { + [ qz_window setContentSize:contentRect.size ]; + current->flags |= (SDL_NOFRAME|SDL_RESIZABLE) & mode_flags; + } } /* For OpenGL, we bind the context to a subview */ @@ -692,9 +728,18 @@ other blitting while waiting on the VBL (and hence results in higher framerates) current->flags |= SDL_PREALLOC; current->flags |= SDL_ASYNCBLIT; - /* Offset below the title bar to fill the full content region */ - current->pixels += ((int)([ qz_window frame ].size.height) - height) * current->pitch; - + /* + current->pixels now points to the window's pixels + We want it to point to the *view's* pixels + */ + { + int vOffset = [ qz_window frame ].size.height - + [ window_view frame ].size.height - [ window_view frame ].origin.y; + + int hOffset = [ window_view frame ].origin.x; + + current->pixels += (vOffset * current->pitch) + hOffset * (device_bpp/8); + } this->UpdateRects = QZ_UpdateRects; this->LockHWSurface = QZ_LockWindow; this->UnlockHWSurface = QZ_UnlockWindow; diff --git a/src/video/quartz/SDL_QuartzWM.m b/src/video/quartz/SDL_QuartzWM.m index 824d3eae7..6f9f4a51b 100644 --- a/src/video/quartz/SDL_QuartzWM.m +++ b/src/video/quartz/SDL_QuartzWM.m @@ -119,28 +119,35 @@ static void QZ_PrivateLocalToGlobal (_THIS, NSPoint *p) { /* Convert SDL coordinate to Cocoa coordinate */ static void QZ_PrivateSDLToCocoa (_THIS, NSPoint *p) { - int height; - if ( CGDisplayIsCaptured (display_id) ) { /* capture signals fullscreen */ - height = CGDisplayPixelsHigh (display_id); + p->y = CGDisplayPixelsHigh (display_id) - p->y - 1; } else { - height = NSHeight ( [ qz_window frame ] ); - if ( [ qz_window styleMask ] & NSTitledWindowMask ) { + NSPoint newPoint; - height -= 22; - } + newPoint = [ window_view convertPoint:*p toView:[ qz_window contentView ] ]; + + *p = newPoint; } - - p->y = height - p->y - 1; } /* Convert Cocoa coordinate to SDL coordinate */ static void QZ_PrivateCocoaToSDL (_THIS, NSPoint *p) { - QZ_PrivateSDLToCocoa (this, p); + if ( CGDisplayIsCaptured (display_id) ) { /* capture signals fullscreen */ + + p->y = CGDisplayPixelsHigh (display_id) - p->y - 1; + } + else { + + NSPoint newPoint; + + newPoint = [ window_view convertPoint:*p fromView:[ qz_window contentView ] ]; + + *p = newPoint; + } } /* Convert SDL coordinate to window server (CoreGraphics) coordinate */ @@ -165,6 +172,7 @@ static CGPoint QZ_PrivateSDLToCG (_THIS, NSPoint *p) { return cgp; } +#if 0 /* Dead code */ /* Convert window server (CoreGraphics) coordinate to SDL coordinate */ static void QZ_PrivateCGToSDL (_THIS, NSPoint *p) { @@ -180,6 +188,7 @@ static void QZ_PrivateCGToSDL (_THIS, NSPoint *p) { QZ_PrivateCocoaToSDL (this, p); } } +#endif /* Dead code */ static void QZ_PrivateWarpCursor (_THIS, int x, int y) { @@ -188,7 +197,6 @@ static void QZ_PrivateWarpCursor (_THIS, int x, int y) { p = NSMakePoint (x, y); cgp = QZ_PrivateSDLToCG (this, &p); - QZ_PrivateCGToSDL (this, &p); /* this is the magic call that fixes cursor "freezing" after warp */ CGSetLocalEventsSuppressionInterval (0.0); diff --git a/src/video/quartz/SDL_QuartzWindow.m b/src/video/quartz/SDL_QuartzWindow.m index 40513b322..1692a92a5 100644 --- a/src/video/quartz/SDL_QuartzWindow.m +++ b/src/video/quartz/SDL_QuartzWindow.m @@ -32,6 +32,7 @@ - (void)miniaturize:(id)sender; - (void)display; - (void)setFrame:(NSRect)frameRect display:(BOOL)flag; - (void)appDidHide:(NSNotification*)note; +- (void)appWillUnhide:(NSNotification*)note; - (void)appDidUnhide:(NSNotification*)note; - (id)initWithContentRect:(NSRect)contentRect styleMask:(unsigned int)styleMask backing:(NSBackingStoreType)backingType defer:(BOOL)flag; @end @@ -63,13 +64,27 @@ - (void)miniaturize:(id)sender - (void)display { /* - This method fires just before the window deminaturizes. - So, it's just the right place to fixup the alpha channel - which - makes the deminiaturize animation look right. + This method fires just before the window deminaturizes from the Dock. + + We'll save the current visible surface, let the window manager redraw any + UI elements, and restore the SDL surface. This way, no expose event + is required, and the deminiaturize works perfectly. */ - if ( (SDL_VideoSurface->flags & SDL_OPENGL) == 0) + SDL_VideoDevice *this = (SDL_VideoDevice*)current_video; + + /* make sure pixels are fully opaque */ + if (! ( SDL_VideoSurface->flags & SDL_OPENGL ) ) QZ_SetPortAlphaOpaque (); - + + /* save current visible SDL surface */ + [ self cacheImageInRect:[ window_view frame ] ]; + + /* let the window manager redraw controls, border, etc */ + [ super display ]; + + /* restore visible SDL surface */ + [ self restoreCachedImage ]; + /* window is visible again */ SDL_PrivateAppActive (1, SDL_APPACTIVE); } @@ -81,30 +96,45 @@ - (void)setFrame:(NSRect)frameRect display:(BOOL)flag If the video surface is NULL, this originated from QZ_SetVideoMode, so don't send the resize event. */ - if (SDL_VideoSurface == NULL) { + SDL_VideoDevice *this = (SDL_VideoDevice*)current_video; + + if (this && SDL_VideoSurface == NULL) { [ super setFrame:frameRect display:flag ]; } - else { + else if (this && qz_window) { - SDL_VideoDevice *this = (SDL_VideoDevice*)current_video; + NSRect newViewFrame; - NSRect sdlRect = [ NSWindow contentRectForFrameRect:frameRect styleMask:[self styleMask] ]; - [ super setFrame:frameRect display:flag ]; - SDL_PrivateResize (sdlRect.size.width, sdlRect.size.height); + + newViewFrame = [ window_view frame ]; + + SDL_PrivateResize (newViewFrame.size.width, newViewFrame.size.height); /* If not OpenGL, we have to update the pixels and pitch */ - if ( ! this->screen->flags & SDL_OPENGL ) { + if ( ! ( SDL_VideoSurface->flags & SDL_OPENGL ) ) { - LockPortBits ( [ window_view qdPort ] ); + CGrafPtr thePort = [ window_view qdPort ]; + LockPortBits ( thePort ); - SDL_VideoSurface->pixels = GetPixBaseAddr ( GetPortPixMap ( [ window_view qdPort ] ) ); - SDL_VideoSurface->pitch = GetPixRowBytes ( GetPortPixMap ( [ window_view qdPort ] ) ); + SDL_VideoSurface->pixels = GetPixBaseAddr ( GetPortPixMap ( thePort ) ); + SDL_VideoSurface->pitch = GetPixRowBytes ( GetPortPixMap ( thePort ) ); + + /* + SDL_VideoSurface->pixels now points to the window's pixels + We want it to point to the *view's* pixels + */ + { + int vOffset = [ qz_window frame ].size.height - + newViewFrame.size.height - newViewFrame.origin.y; + + int hOffset = newViewFrame.origin.x; + + SDL_VideoSurface->pixels += (vOffset * SDL_VideoSurface->pitch) + hOffset * (device_bpp/8); + } - SDL_VideoSurface->pixels += ((int)[ self frame ].size.height - (int)sdlRect.size.height) * SDL_VideoSurface->pitch; - - UnlockPortBits ( [ window_view qdPort ] ); + UnlockPortBits ( thePort ); } } } @@ -114,8 +144,28 @@ - (void)appDidHide:(NSNotification*)note SDL_PrivateAppActive (0, SDL_APPACTIVE); } +- (void)appWillUnhide:(NSNotification*)note +{ + SDL_VideoDevice *this = (SDL_VideoDevice*)current_video; + + if ( this ) { + + /* make sure pixels are fully opaque */ + if (! ( SDL_VideoSurface->flags & SDL_OPENGL ) ) + QZ_SetPortAlphaOpaque (); + + /* save current visible SDL surface */ + [ self cacheImageInRect:[ window_view frame ] ]; + } +} + - (void)appDidUnhide:(NSNotification*)note { + /* restore cached image, since it may not be current, post expose event too */ + [ self restoreCachedImage ]; + + //SDL_PrivateExpose (); + SDL_PrivateAppActive (1, SDL_APPACTIVE); } @@ -127,6 +177,9 @@ - (id)initWithContentRect:(NSRect)contentRect styleMask:(unsigned int)styleMask [ [ NSNotificationCenter defaultCenter ] addObserver:self selector:@selector(appDidUnhide:) name:NSApplicationDidUnhideNotification object:NSApp ]; + + [ [ NSNotificationCenter defaultCenter ] addObserver:self + selector:@selector(appWillUnhide:) name:NSApplicationWillUnhideNotification object:NSApp ]; return [ super initWithContentRect:contentRect styleMask:styleMask backing:backingType defer:flag ]; }