From 2ee1c5751a950353cc44d578cd778df799177468 Mon Sep 17 00:00:00 2001 From: ceylo Date: Tue, 23 Feb 2010 09:54:16 +0000 Subject: [PATCH] Reorganized private window implementation to allow using objects for window import (especially to allow Qt [Cocoa version] use even it does not work because Qt windows are deferred; it still works for Cocoa though until windows are not deferred). Renamed Objective-C classes with sfPriv prefix to prevent conflict with user Objective-C classes. git-svn-id: https://sfml.svn.sourceforge.net/svnroot/sfml/trunk@1421 4e206d99-4929-0410-ac5d-dfc041789085 --- src/SFML/Window/Cocoa/AppController.h | 10 +- src/SFML/Window/Cocoa/AppController.mm | 48 +- src/SFML/Window/Cocoa/GLKit.h | 131 ++-- src/SFML/Window/Cocoa/GLKit.mm | 783 ++++++++++++++-------- src/SFML/Window/Cocoa/WindowImplCocoa.hpp | 8 +- src/SFML/Window/Cocoa/WindowImplCocoa.mm | 87 ++- 6 files changed, 664 insertions(+), 403 deletions(-) diff --git a/src/SFML/Window/Cocoa/AppController.h b/src/SFML/Window/Cocoa/AppController.h index e87fe3a30..de2d055f1 100644 --- a/src/SFML/Window/Cocoa/AppController.h +++ b/src/SFML/Window/Cocoa/AppController.h @@ -36,10 +36,10 @@ enum { CleanScreen }; -@class WindowWrapper; -@interface AppController : NSObject { +@class sfPrivWindow; +@interface sfPrivAppController : NSObject { BOOL myOwningEventLoop; - WindowWrapper *myFullscreenWrapper; + sfPrivWindow *myFullscreenWrapper; NSAutoreleasePool *myMainPool; sf::VideoMode myDesktopMode; sf::VideoMode myPrevMode; @@ -48,7 +48,7 @@ enum { //////////////////////////////////////////////////////////// /// Return the shared AppController instance. Make one if needed. //////////////////////////////////////////////////////////// -+ (AppController *)sharedController; ++ (sfPrivAppController *)sharedController; //////////////////////////////////////////////////////////// /// Returns the primay computer's screen @@ -76,7 +76,7 @@ enum { /// Set @window as the current fullscreen window /// Change the screen resolution if needed according to @window and @fullscreenMode //////////////////////////////////////////////////////////// -- (void)setFullscreenWindow:(WindowWrapper *)window mode:(sf::VideoMode *)fullscreenMode; +- (void)setFullscreenWindow:(sfPrivWindow *)window mode:(sf::VideoMode *)fullscreenMode; //////////////////////////////////////////////////////////// /// Perform fade operation where 'operation' is one of { FillScreen, CleanScreen} diff --git a/src/SFML/Window/Cocoa/AppController.mm b/src/SFML/Window/Cocoa/AppController.mm index 5a90c21c3..1e0696612 100644 --- a/src/SFML/Window/Cocoa/AppController.mm +++ b/src/SFML/Window/Cocoa/AppController.mm @@ -57,7 +57,7 @@ @end -@implementation AppController +@implementation sfPrivAppController //////////////////////////////////////////////////////////// @@ -129,10 +129,10 @@ //////////////////////////////////////////////////////////// /// Return the shared AppController instance. Make one if needed. //////////////////////////////////////////////////////////// -+ (AppController *)sharedController ++ (sfPrivAppController *)sharedController { // AppController singleton object - static AppController *shared = [[AppController alloc] init]; + static sfPrivAppController *shared = [[sfPrivAppController alloc] init]; return shared; } @@ -192,7 +192,7 @@ if (myFullscreenWrapper) { myPrevMode = sf::VideoMode::GetDesktopMode(); - CFDictionaryRef displayMode = CGDisplayBestModeForParameters ([AppController primaryScreen], + CFDictionaryRef displayMode = CGDisplayBestModeForParameters ([sfPrivAppController primaryScreen], myDesktopMode.BitsPerPixel, myDesktopMode.Width, myDesktopMode.Height, @@ -202,7 +202,7 @@ [[myFullscreenWrapper window] setAlphaValue:0.0f]; // Switch to the wished display mode - CGDisplaySwitchToMode([AppController primaryScreen], displayMode); + CGDisplaySwitchToMode([sfPrivAppController primaryScreen], displayMode); } } @@ -213,7 +213,7 @@ - (void)applicationWillActivate:(NSNotification *)aNotification { if (myFullscreenWrapper) { - CFDictionaryRef displayMode = CGDisplayBestModeForParameters ([AppController primaryScreen], + CFDictionaryRef displayMode = CGDisplayBestModeForParameters ([sfPrivAppController primaryScreen], myPrevMode.BitsPerPixel, myPrevMode.Width, myPrevMode.Height, @@ -221,7 +221,7 @@ [NSMenu setMenuBarVisible:NO]; // Switch to the wished display mode - CGDisplaySwitchToMode([AppController primaryScreen], displayMode); + CGDisplaySwitchToMode([sfPrivAppController primaryScreen], displayMode); // Show the fullscreen window if existing if (myFullscreenWrapper) @@ -404,13 +404,13 @@ /// Set @window as the current fullscreen window /// Change the screen resolution if needed according to @window and @fullscreenMode //////////////////////////////////////////////////////////// -- (void)setFullscreenWindow:(WindowWrapper *)aWrapper mode:(sf::VideoMode *)fullscreenMode +- (void)setFullscreenWindow:(sfPrivWindow *)aWindow mode:(sf::VideoMode *)fullscreenMode { // If we have a fullscreen window and want to remove it - if (aWrapper == nil && myFullscreenWrapper) + if (aWindow == nil && myFullscreenWrapper) { // Get the CoreGraphics display mode according to the desktop mode - CFDictionaryRef displayMode = CGDisplayBestModeForParameters ([AppController primaryScreen], + CFDictionaryRef displayMode = CGDisplayBestModeForParameters ([sfPrivAppController primaryScreen], myDesktopMode.BitsPerPixel, myDesktopMode.Width, myDesktopMode.Height, @@ -422,7 +422,7 @@ #endif // Switch to the desktop display mode - CGDisplaySwitchToMode([AppController primaryScreen], displayMode); + CGDisplaySwitchToMode([sfPrivAppController primaryScreen], displayMode); // Close the window [[myFullscreenWrapper window] close]; @@ -438,13 +438,13 @@ // Release the saved window wrapper myFullscreenWrapper = nil; } - else if (aWrapper) + else if (aWindow) { // else if we want to SET fullscreen assert(fullscreenMode != NULL); // Get the CoreGraphics display mode according to the given sf mode - CFDictionaryRef displayMode = CGDisplayBestModeForParameters ([AppController primaryScreen], + CFDictionaryRef displayMode = CGDisplayBestModeForParameters ([sfPrivAppController primaryScreen], fullscreenMode->BitsPerPixel, fullscreenMode->Width, fullscreenMode->Height, @@ -465,7 +465,7 @@ { // Switch to the wished display mode myPrevMode = *fullscreenMode; - CGDisplaySwitchToMode([AppController primaryScreen], displayMode); + CGDisplaySwitchToMode([sfPrivAppController primaryScreen], displayMode); } if (myFullscreenWrapper) @@ -474,8 +474,8 @@ } // Open and center the window - [[aWrapper window] makeKeyAndOrderFront:nil]; - [[aWrapper window] center]; + [[aWindow window] makeKeyAndOrderFront:nil]; + [[aWindow window] center]; #if ENABLE_FADE_OPERATIONS // Fade to normal screen @@ -483,11 +483,11 @@ #endif // Save the fullscreen wrapper - myFullscreenWrapper = aWrapper; + myFullscreenWrapper = aWindow; } else { - std::cerr << "Inconcistency error for arguments given to -[AppController setFullscreenWindow:mode:]" << std::endl; + std::cerr << "Inconcistency error for arguments given to -[sfPrivAppController setFullscreenWindow:mode:]" << std::endl; } } @@ -514,7 +514,7 @@ if (!result) { // Capture display but do not fill the screen with black // so that we can see the fade operation - capture = CGDisplayCaptureWithOptions([AppController primaryScreen], kCGCaptureNoFill); + capture = CGDisplayCaptureWithOptions([sfPrivAppController primaryScreen], kCGCaptureNoFill); if (!capture) { // Do the increasing fade operation @@ -524,11 +524,11 @@ 0.0f, 0.0f, 0.0f, sync); // Now, release the non black-filling capture - CGDisplayRelease([AppController primaryScreen]); + CGDisplayRelease([sfPrivAppController primaryScreen]); // And capture with filling // so that we don't see the switching in the meantime - CGDisplayCaptureWithOptions([AppController primaryScreen], kCGCaptureNoOptions); + CGDisplayCaptureWithOptions([sfPrivAppController primaryScreen], kCGCaptureNoOptions); } prevToken = token; @@ -541,10 +541,10 @@ if (!result) { if (!capture) { // Release the black-filling capture - CGDisplayRelease([AppController primaryScreen]); + CGDisplayRelease([sfPrivAppController primaryScreen]); // Capture the display but do not fill with black (still for the fade operation) - CGDisplayCaptureWithOptions([AppController primaryScreen], kCGCaptureNoFill); + CGDisplayCaptureWithOptions([sfPrivAppController primaryScreen], kCGCaptureNoFill); // Do the decreasing fading CGDisplayFade(token, time, @@ -560,7 +560,7 @@ } // Release the captured display - CGDisplayRelease([AppController primaryScreen]); + CGDisplayRelease([sfPrivAppController primaryScreen]); } } } diff --git a/src/SFML/Window/Cocoa/GLKit.h b/src/SFML/Window/Cocoa/GLKit.h index ca916c781..f3f581a91 100644 --- a/src/SFML/Window/Cocoa/GLKit.h +++ b/src/SFML/Window/Cocoa/GLKit.h @@ -33,9 +33,6 @@ /// Window independant OpenGL context class //////////////////////////////////////////////////////////// @interface GLContext : NSOpenGLContext -{ - -} //////////////////////////////////////////////////////////// /// Return the shared OpenGL context instance (making one if needed) @@ -64,13 +61,22 @@ //////////////////////////////////////////////////////////// /// Make a new view according the the rect @frame, /// the video mode @mode, the window settings @settings -/// and the sf window delegate @delegate /// @delegate must not be null //////////////////////////////////////////////////////////// - (id)initWithFrame:(NSRect)frame mode:(const sf::VideoMode&)mode - settings:(sf::WindowSettings&)settings - delegate:(sf::priv::WindowImplCocoa *)delegate; + settings:(sf::WindowSettings&)settings; + + +//////////////////////////////////////////////////////////// +/// Sets @aDelegate as the view delegate +//////////////////////////////////////////////////////////// +- (void)setDelegate:(sf::priv::WindowImplCocoa *)aDelegate; + +//////////////////////////////////////////////////////////// +/// Returns the view delegate +//////////////////////////////////////////////////////////// +- (sf::priv::WindowImplCocoa *)delegate; //////////////////////////////////////////////////////////// /// Finish view setting (after having added it to the window) @@ -94,53 +100,16 @@ @end - //////////////////////////////////////////////////////////// -/// WindowWrapper class : handles both imported and self-built windows +/// Parent class for handling general SFML window stuff //////////////////////////////////////////////////////////// -@interface WindowWrapper : NSObject +@interface sfPrivWindow : NSObject { +@private NSWindow *myWindow; GLView *myView; - sf::VideoMode myFullscreenMode; - bool myIsFullscreen; } -//////////////////////////////////////////////////////////// -/// Make a new window wrapper according to the window settings @attribs, -/// the video mode @mode, the window style @style, the window title @title -/// and the sf window implementation delegate @delegate -//////////////////////////////////////////////////////////// -- (id)initWithSettings:(sf::WindowSettings&)attribs - videoMode:(sf::VideoMode&)mode - style:(unsigned long)style - title:(NSString *)title - delegate:(sf::priv::WindowImplCocoa *)delegate; - -//////////////////////////////////////////////////////////// -/// Make a new window wrapper by importing @window and according to -/// the window settings @params and the sf window implementation delegate -/// @delegate -/// @window and @delegate must not be null -//////////////////////////////////////////////////////////// -- (id)initWithWindow:(NSWindow *)window - settings:(sf::WindowSettings&)params - delegate:(sf::priv::WindowImplCocoa *)delegate; - -//////////////////////////////////////////////////////////// -/// Make a new window wrapper by importing @window if it's not null and according to -/// the window settings @params and the sf window implementation delegate -/// @delegate; or by creating a new window if @window is null. In this case @title -/// must therefore not be null and @params must be valid. -/// @delegate must never be null -//////////////////////////////////////////////////////////// -- (id)initWithWindow:(NSWindow *)window - settings:(sf::WindowSettings&)params - videoMode:(sf::VideoMode&)mode - style:(unsigned long)style - title:(NSString *)title - delegate:(sf::priv::WindowImplCocoa *)delegate; - //////////////////////////////////////////////////////////// /// Return a reference to the internal Cocoa window //////////////////////////////////////////////////////////// @@ -149,7 +118,17 @@ //////////////////////////////////////////////////////////// /// Return a reference to the internal Cocoa OpenGL view //////////////////////////////////////////////////////////// -- (GLView *)glView; +- (GLView *)view; + +//////////////////////////////////////////////////////////// +/// Sets @aDelegate as the window delegate +//////////////////////////////////////////////////////////// +- (void)setDelegate:(sf::priv::WindowImplCocoa *)aDelegate; + +//////////////////////////////////////////////////////////// +/// Returns the window delegate +//////////////////////////////////////////////////////////// +- (sf::priv::WindowImplCocoa *)delegate; //////////////////////////////////////////////////////////// /// Forward call to set the window position on screen @@ -193,3 +172,61 @@ @end +//////////////////////////////////////////////////////////// +/// Class for creating new SFML windows from informations +//////////////////////////////////////////////////////////// +@interface sfPrivOwnedWindow : sfPrivWindow +{ +@private + sf::VideoMode myFullscreenMode; + bool myIsFullscreen; +} + +//////////////////////////////////////////////////////////// +/// Creates and returns a new SFML window handler with +/// the given parameters +//////////////////////////////////////////////////////////// +- (id)initWithVideoMode:(sf::VideoMode&)aMode + settings:(sf::WindowSettings&)someSettings + style:(unsigned long)aStyle + title:(NSString *)aTitle; + +//////////////////////////////////////////////////////////// +/// Returns the window's fullscreen state +//////////////////////////////////////////////////////////// +- (BOOL)isFullscreen; + +@end + + +//////////////////////////////////////////////////////////// +/// Class for creating SFML windows from Cocoa windows +//////////////////////////////////////////////////////////// +@interface sfPrivImportedWindow : sfPrivWindow + +//////////////////////////////////////////////////////////// +/// Returns a new SFML window handler with the given window +/// and parameters +//////////////////////////////////////////////////////////// +- (id)initWithWindow:(NSWindow *)aWindow + settings:(sf::WindowSettings&)someSettings; + +@end + + +//////////////////////////////////////////////////////////// +/// Class for creating SFML windows from Cocoa views +//////////////////////////////////////////////////////////// +@interface sfPrivImportedView : sfPrivWindow +{ + NSView *parentView; +} + +//////////////////////////////////////////////////////////// +/// Returns a new SFML window handler with the given view +/// and parameters +//////////////////////////////////////////////////////////// +- (id)initWithView:(NSView *)aView + settings:(sf::WindowSettings&)someSettings; + +@end diff --git a/src/SFML/Window/Cocoa/GLKit.mm b/src/SFML/Window/Cocoa/GLKit.mm index 8793f23b5..a0b319656 100644 --- a/src/SFML/Window/Cocoa/GLKit.mm +++ b/src/SFML/Window/Cocoa/GLKit.mm @@ -33,6 +33,35 @@ #import +@interface sfPrivWindow (Protected) + +//////////////////////////////////////////////////////////// +/// Registers a reference to the internal Cocoa window +//////////////////////////////////////////////////////////// +- (void)setWindow:(NSWindow *)aWindow; + +//////////////////////////////////////////////////////////// +/// Registers the the OpenGL view and adds it to its parent container +//////////////////////////////////////////////////////////// +- (void)putOpenGLView:(GLView *)aView; + +//////////////////////////////////////////////////////////// +/// Registers a reference to the internal Cocoa OpenGL view +//////////////////////////////////////////////////////////// +- (void)setView:(GLView *)aView; + +@end + +@interface sfPrivOwnedWindow (Private) + +//////////////////////////////////////////////////////////// +/// Sets the window's fullscreen state +//////////////////////////////////////////////////////////// +- (void)setFullscreen:(BOOL)aFlag; + +@end + + //////////////////////////////////////////////////////////// /// Window independant OpenGL context class //////////////////////////////////////////////////////////// @@ -72,7 +101,9 @@ // I've no way to fix this for now. if (attribs.AntialiasingLevel) - std::cerr << "Warning: antialiasing settings are inhibited under Mac OS X for technical reasons" << std::endl; + std::cerr + << "Warning: antialiasing settings are inhibited under Mac OS X for technical reasons" + << std::endl; NSOpenGLPixelFormat *myPixelFormat = nil; unsigned idx = 0; @@ -87,7 +118,7 @@ // Force use of first screen //ctxtAttribs[idx++] = NSOpenGLPFAScreenMask; - //ctxtAttribs[idx++] = CGDisplayIDToOpenGLDisplayMask([AppController primaryScreen]); + //ctxtAttribs[idx++] = CGDisplayIDToOpenGLDisplayMask([sfPrivAppController primaryScreen]); // windowed context (even fullscreen mode uses a window) ctxtAttribs[idx++] = NSOpenGLPFAWindow; @@ -155,10 +186,7 @@ - (id)initWithFrame:(NSRect)frame mode:(const sf::VideoMode&)mode settings:(sf::WindowSettings&)settings - delegate:(sf::priv::WindowImplCocoa *)delegate { - assert(delegate != NULL); - // make the view self = [super initWithFrame:frame pixelFormat:nil]; @@ -182,9 +210,6 @@ selector:@selector(viewFrameDidChange:) name:NSViewFrameDidChangeNotification object:self]; - - // Save the delegate - myDelegate = delegate; } return self; @@ -203,6 +228,22 @@ [super dealloc]; } +//////////////////////////////////////////////////////////// +/// Sets @aDelegate as the view delegate +//////////////////////////////////////////////////////////// +- (void)setDelegate:(sf::priv::WindowImplCocoa *)aDelegate +{ + myDelegate = aDelegate; +} + +//////////////////////////////////////////////////////////// +/// Returns the view delegate +//////////////////////////////////////////////////////////// +- (sf::priv::WindowImplCocoa *)delegate +{ + return myDelegate; +} + //////////////////////////////////////////////////////////// /// Finish view setting (after having added it to the window) @@ -437,215 +478,9 @@ @end -//////////////////////////////////////////////////////////// -/// WindowWrapper class : handles both imported and self-built windows -//////////////////////////////////////////////////////////// -@implementation WindowWrapper -//////////////////////////////////////////////////////////// -/// Make a new window wrapper according to the window settings @attribs, -/// the video mode @mode, the window style @style, the window title @title -/// and the sf window implementation delegate @delegate -//////////////////////////////////////////////////////////// -- (id)initWithSettings:(sf::WindowSettings&)params - videoMode:(sf::VideoMode&)mode - style:(unsigned long)style - title:(NSString *)title - delegate:(sf::priv::WindowImplCocoa *)delegate -{ - return [self initWithWindow:nil - settings:params - videoMode:mode - style:style - title:title - delegate:delegate]; -} +@implementation sfPrivWindow - -//////////////////////////////////////////////////////////// -/// Make a new window wrapper by importing @window and according to -/// the window settings @params and the sf window implementation delegate -/// @delegate -/// @window and @delegate must not be null -//////////////////////////////////////////////////////////// -- (id)initWithWindow:(NSWindow *)window - settings:(sf::WindowSettings&)params - delegate:(sf::priv::WindowImplCocoa *)delegate -{ - sf::VideoMode mode([[myWindow contentView] frame].size.width, [[myWindow contentView] frame].size.height); - return [self initWithWindow:window - settings:params - videoMode:mode - style:0 - title:nil - delegate:delegate]; -} - - -//////////////////////////////////////////////////////////// -/// Make a new window wrapper by importing @window if it's not null and according to -/// the window settings @params and the sf window implementation delegate -/// @delegate; or by creating a new window if @window is null. In this case @title -/// must therefore not be null and @params must be valid. -/// @delegate must never be null -//////////////////////////////////////////////////////////// -- (id)initWithWindow:(NSWindow *)window - settings:(sf::WindowSettings&)params - videoMode:(sf::VideoMode&)mode - style:(unsigned long)style - title:(NSString *)title - delegate:(sf::priv::WindowImplCocoa *)delegate -{ - assert(delegate != NULL); - - self = [super init]; - - if (self) - { - if (window) { - myWindow = [window retain]; - } else { - assert(title != nil); - - NSRect frame = NSMakeRect (0.0f, 0.0f, (float) mode.Width, (float) mode.Height); - unsigned int mask = 0; - - if (style & sf::Style::Fullscreen) { - myIsFullscreen = true; - - // Check display mode and put new values in 'mode' if needed - boolean_t exact = true; - - CFDictionaryRef properties = CGDisplayBestModeForParameters([AppController primaryScreen], mode.BitsPerPixel, - mode.Width, mode.Height, &exact); - - if (!properties) { - std::cerr << "Unable to get a display mode with the given parameters" << std::endl; - [self autorelease]; - return nil; - } - - if (exact == false) { - CFNumberGetValue((CFNumberRef) CFDictionaryGetValue(properties, kCGDisplayWidth), - kCFNumberIntType, &mode.Width); - - CFNumberGetValue((CFNumberRef) CFDictionaryGetValue(properties, kCGDisplayHeight), - kCFNumberIntType, &mode.Height); - - CFNumberGetValue((CFNumberRef) CFDictionaryGetValue(properties, kCGDisplayBitsPerPixel), - kCFNumberIntType, &mode.BitsPerPixel); - - } - } - - // We grab options from WindowStyle and add them to our window mask - if (style & sf::Style::None || style & sf::Style::Fullscreen) { - mask |= NSBorderlessWindowMask; - - - - } else { - if (style & sf::Style::Titlebar) { - mask |= NSTitledWindowMask; - mask |= NSMiniaturizableWindowMask; - } - - if (style & sf::Style::Resize) { - mask |= NSTitledWindowMask; - mask |= NSMiniaturizableWindowMask; - mask |= NSResizableWindowMask; - } - - if (style & sf::Style::Close) { - mask |= NSTitledWindowMask; - mask |= NSClosableWindowMask; - mask |= NSMiniaturizableWindowMask; - } - } - - // Now we make the window with the values we got - // Note: defer flag set to NO to be able to use OpenGL in our window - myWindow = [[NSWindow alloc] initWithContentRect:frame - styleMask:mask - backing:NSBackingStoreBuffered - defer:NO]; - - if (myWindow) { - // We set title and window position - [myWindow setTitle:title]; - [myWindow center]; - } else { - std::cerr << "Unable to create the Cocoa window" << std::endl; - [self autorelease]; - return nil; - } - } - - // Make the OpenGL view - myView = [[GLView alloc] initWithFrame:[[myWindow contentView] frame] - mode:mode - settings:params - delegate:delegate]; - - if (myView) { - // Finish setting up the view and window - // Add the view to our window and tell it to the view - [[myWindow contentView] addSubview:myView]; - [myView finishInitialization]; - - NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; - - // We want to know when our window got the focus - [nc addObserver:self - selector:@selector(windowDidBecomeMain:) - name:NSWindowDidBecomeMainNotification - object:myWindow]; - - // We want to know when our window lost the focus - [nc addObserver:self - selector:@selector(windowDidResignMain:) - name:NSWindowDidResignMainNotification - object:myWindow]; - - // We want to know when the user closes the window - [nc addObserver:self - selector:@selector(windowWillClose:) - name:NSWindowWillCloseNotification - object:myWindow]; - - // I want to re-center the window if it's a full screen one and moved by Spaces - [nc addObserver:self - selector:@selector(windowDidMove:) - name:NSWindowDidMoveNotification - object:myWindow]; - - // Needed not to make application crash when releasing the window in our destructor - // (I prefer to take control of everything :P) - [myWindow setReleasedWhenClosed:NO]; - [myWindow setAcceptsMouseMovedEvents:YES]; - - } else { - std::cerr << "Unable to create the OpenGL view" << std::endl; - [self autorelease]; - return nil; - } - - if (myIsFullscreen) { - myFullscreenMode = mode; - - // Using this because full screen window was not always - // in front of the other application windows when unhiding app - [myWindow setLevel:NSFloatingWindowLevel]; - } - } - - return self; -} - - -//////////////////////////////////////////////////////////// -/// Clean the window wrapper -//////////////////////////////////////////////////////////// - (void)dealloc { NSAutoreleasePool *localPool = [[NSAutoreleasePool alloc] init]; @@ -656,93 +491,173 @@ [self show:false]; // Release the window and view - [myView removeFromSuperviewWithoutNeedingDisplay]; + [[self view] removeFromSuperviewWithoutNeedingDisplay]; - [myView release]; - [myWindow release]; + [self setWindow:nil]; + [self setView:nil]; + [self setDelegate:nil]; [super dealloc]; [localPool release]; } +//////////////////////////////////////////////////////////// +/// Registers a reference to the internal Cocoa window +//////////////////////////////////////////////////////////// +- (void)setWindow:(NSWindow *)aWindow +{ + if (myWindow != aWindow) + { + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + + // Drop the observers on the previously set window + if ([self window]) { + [nc removeObserver:self + name:NSWindowDidBecomeMainNotification + object:[self window]]; + [nc removeObserver:self + name:NSWindowDidResignMainNotification + object:[self window]]; + [nc removeObserver:self + name:NSWindowWillCloseNotification + object:[self window]]; + } + + [myWindow release]; + myWindow = [aWindow retain]; + + // Set the new observers + // We want to know when our window got the focus + [nc addObserver:self + selector:@selector(windowDidBecomeMain:) + name:NSWindowDidBecomeMainNotification + object:[self window]]; + + // We want to know when our window lost the focus + [nc addObserver:self + selector:@selector(windowDidResignMain:) + name:NSWindowDidResignMainNotification + object:[self window]]; + + // We want to know when the user closes the window + [nc addObserver:self + selector:@selector(windowWillClose:) + name:NSWindowWillCloseNotification + object:[self window]]; + + } +} //////////////////////////////////////////////////////////// /// Return a reference to the internal Cocoa window //////////////////////////////////////////////////////////// - (NSWindow *)window { - return myWindow; + return [[myWindow retain] autorelease]; } +//////////////////////////////////////////////////////////// +/// Registers the the OpenGL view and adds it to its parent container +//////////////////////////////////////////////////////////// +- (void)putOpenGLView:(GLView *)aView +{ + [self setView:aView]; + + // Finish setting up the view and window + // Add the view to our window and tell it to the view + [[[self window] contentView] addSubview:[self view]]; + [[self view] finishInitialization]; +} + +//////////////////////////////////////////////////////////// +/// Registers a reference to the internal Cocoa OpenGL view +//////////////////////////////////////////////////////////// +- (void)setView:(GLView *)aView +{ + if (myView != aView) + { + [myView release]; + myView = [aView retain]; + } +} + //////////////////////////////////////////////////////////// /// Return a reference to the internal Cocoa OpenGL view //////////////////////////////////////////////////////////// -- (GLView *)glView +- (GLView *)view { - return myView; + return [[myView retain] autorelease]; } +//////////////////////////////////////////////////////////// +/// Sets @aDelegate as the window delegate +//////////////////////////////////////////////////////////// +- (void)setDelegate:(sf::priv::WindowImplCocoa *)aDelegate +{ + [[self view] setDelegate:aDelegate]; +} + +//////////////////////////////////////////////////////////// +/// Returns the window delegate +//////////////////////////////////////////////////////////// +- (sf::priv::WindowImplCocoa *)delegate +{ + return [[self view] delegate]; +} //////////////////////////////////////////////////////////// /// Forward call to set the window position on screen //////////////////////////////////////////////////////////// - (void)setPosition:(NSPoint)pos { - assert(myWindow != nil); + NSAssert([self window] != nil, @"expected valid window"); - if (!myIsFullscreen) { - // Flip Y and set window position - pos.y = [[myWindow screen] frame].size.height - pos.y; - [myWindow setFrameTopLeftPoint:pos]; - } + // Flip Y and set window position + pos.y = [[[self window] screen] frame].size.height - pos.y; + [[self window] setFrameTopLeftPoint:pos]; } - //////////////////////////////////////////////////////////// /// Forward call to set the window size //////////////////////////////////////////////////////////// - (void)setSize:(NSSize)size { - assert(myWindow != nil); + NSAssert([self window] != nil, @"expected valid window"); - if (!myIsFullscreen) { - [myWindow setFrame:NSMakeRect([myWindow frame].origin.x, - [myWindow frame].origin.y, - size.width, size.height) - display:YES]; - } + [[self window] setFrame:NSMakeRect([[self window] frame].origin.x, + [[self window] frame].origin.y, + size.width, size.height) + display:YES]; } - //////////////////////////////////////////////////////////// /// Return the mouse location relative to the internal window //////////////////////////////////////////////////////////// - (NSPoint)mouseLocation { - assert(myWindow != nil); + NSAssert([self window] != nil, @"expected valid window"); - NSPoint relativeLocation = [myWindow convertScreenToBase:[NSEvent mouseLocation]]; - relativeLocation.y = [[self glView] frame].size.height - relativeLocation.y; + NSPoint relativeLocation = [[self window] convertScreenToBase:[NSEvent mouseLocation]]; + relativeLocation.y = [[self view] frame].size.height - relativeLocation.y; return relativeLocation; } - //////////////////////////////////////////////////////////// /// Return whether the mouse is on our window //////////////////////////////////////////////////////////// - (BOOL)mouseInside { - assert(myWindow != nil); - assert(myView != nil); + NSAssert([self window] != nil, @"expected valid window"); + NSAssert([self view] != nil, @"expected valid OpenGL view"); BOOL flag = NO; - if ([myWindow isVisible]) { - NSPoint relativeToWindow = [myWindow mouseLocationOutsideOfEventStream]; - NSPoint relativeToView = [myView convertPoint:relativeToWindow fromView:nil]; + if ([[self window] isVisible]) { + NSPoint relativeToWindow = [[self window] mouseLocationOutsideOfEventStream]; + NSPoint relativeToView = [[self view] convertPoint:relativeToWindow fromView:nil]; - if (NSPointInRect (relativeToView, [myView bounds])) + if (NSPointInRect (relativeToView, [[self view] bounds])) { flag = YES; } @@ -751,32 +666,23 @@ return flag; } - //////////////////////////////////////////////////////////// /// Close or open the window //////////////////////////////////////////////////////////// - (void)show:(bool)flag { - assert(myWindow != nil); + NSAssert([self window] != nil, @"expected valid window"); - if (flag && ![myWindow isVisible]) { + if (flag && ![[self window] isVisible]) { // Wanna open the closed window - if (myIsFullscreen) { - [[AppController sharedController] setFullscreenWindow:self mode:&myFullscreenMode]; - } else { - // Show the window - [myWindow makeKeyAndOrderFront:nil]; - } - } else if (!flag && [myWindow isVisible]) { + // Show the window + [[self window] makeKeyAndOrderFront:nil]; + } else if (!flag && [[self window] isVisible]) { // Wanna close the opened window - if (myIsFullscreen) { - [[AppController sharedController] setFullscreenWindow:nil mode:NULL]; - } else { - // Close the window - [myWindow close]; - } + // Close the window + [[self window] close]; } } @@ -786,31 +692,28 @@ //////////////////////////////////////////////////////////// - (void)enableVerticalSync:(bool)flag { - assert(myView != nil); - [myView enableVerticalSync:flag]; + NSAssert([self view] != nil, @"expected valid OpenGL view"); + [[self view] enableVerticalSync:flag]; } - //////////////////////////////////////////////////////////// /// Forward 'setActive' call the the OpenGL view //////////////////////////////////////////////////////////// - (void)setActive:(bool)flag { - assert(myView != nil); - [myView setActive:flag]; + NSAssert([self view] != nil, @"expected valid OpenGL view"); + [[self view] setActive:flag]; } - //////////////////////////////////////////////////////////// /// Forward call to flush the OpenGL view //////////////////////////////////////////////////////////// - (void)flushBuffer { - assert(myView != nil); - [myView flushBuffer]; + NSAssert([self view] != nil, @"expected valid OpenGL view"); + [[self view] flushBuffer]; } - //////////////////////////////////////////////////////////// /// Notification method receiver when the window gains focus //////////////////////////////////////////////////////////// @@ -819,7 +722,7 @@ sf::Event ev; ev.Type = sf::Event::GainedFocus; - [myView pushEvent:ev]; + [[self view] pushEvent:ev]; } @@ -831,7 +734,7 @@ sf::Event ev; ev.Type = sf::Event::LostFocus; - [myView pushEvent:ev]; + [[self view] pushEvent:ev]; } @@ -843,10 +746,171 @@ sf::Event ev; ev.Type = sf::Event::Closed; - [myView pushEvent:ev]; + [[self view] pushEvent:ev]; } +@end + + +@implementation sfPrivOwnedWindow + +- (id)initWithVideoMode:(sf::VideoMode&)aMode + settings:(sf::WindowSettings&)someSettings + style:(unsigned long)aStyle + title:(NSString *)aTitle +{ + self = [super init]; + if (self) + { + if (aStyle & sf::Style::Fullscreen) { + [self setFullscreen:YES]; + } + + NSRect frame = NSMakeRect (0.0f, 0.0f, (float) aMode.Width, (float) aMode.Height); + unsigned int mask = 0; + + if (aStyle & sf::Style::Fullscreen) { + // Check display mode and put new values in 'mode' if needed + boolean_t exact = true; + + CFDictionaryRef properties = + CGDisplayBestModeForParameters([sfPrivAppController primaryScreen], + aMode.BitsPerPixel, + aMode.Width, + aMode.Height, + &exact); + + if (!properties) { + std::cerr + << "Unable to get a display mode with the given parameters" + << std::endl; + + [self autorelease]; + return nil; + } + + if (exact == false) { + CFNumberGetValue((CFNumberRef) CFDictionaryGetValue(properties, + kCGDisplayWidth), + kCFNumberIntType, &aMode.Width); + + CFNumberGetValue((CFNumberRef) CFDictionaryGetValue(properties, + kCGDisplayHeight), + kCFNumberIntType, &aMode.Height); + + CFNumberGetValue((CFNumberRef) CFDictionaryGetValue(properties, + kCGDisplayBitsPerPixel), + kCFNumberIntType, &aMode.BitsPerPixel); + + } + } + + // We grab options from WindowStyle and add them to our window mask + if (aStyle & sf::Style::None || aStyle & sf::Style::Fullscreen) { + mask |= NSBorderlessWindowMask; + } else { + if (aStyle & sf::Style::Titlebar) { + mask |= NSTitledWindowMask; + mask |= NSMiniaturizableWindowMask; + } + + if (aStyle & sf::Style::Resize) { + mask |= NSTitledWindowMask; + mask |= NSMiniaturizableWindowMask; + mask |= NSResizableWindowMask; + } + + if (aStyle & sf::Style::Close) { + mask |= NSTitledWindowMask; + mask |= NSClosableWindowMask; + mask |= NSMiniaturizableWindowMask; + } + } + + // Now we make the window with the values we got + // Note: defer flag set to NO to be able to use OpenGL in our window + NSWindow *newWindow = [[NSWindow alloc] + initWithContentRect:frame + styleMask:mask + backing:NSBackingStoreBuffered + defer:NO]; + + if (newWindow) { + [self setWindow:[newWindow autorelease]]; + } else { + std::cerr << "Unable to create the Cocoa window" << std::endl; + [self autorelease]; + return nil; + } + + // We set title and window position + [[self window] setTitle:aTitle != nil ? aTitle : @""]; + [[self window] center]; + + // Make the OpenGL view + GLView *newView = [[GLView alloc] + initWithFrame:[[[self window] contentView] frame] + mode:aMode + settings:someSettings]; + + if (!newView) { + std::cerr << "Unable to create the OpenGL view" << std::endl; + [self autorelease]; + return nil; + } + + // Put our view in the window + [self putOpenGLView:[newView autorelease]]; + + // I want to re-center the window if it's a full screen one and moved by Spaces + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(windowDidMove:) + name:NSWindowDidMoveNotification + object:[self window]]; + + // Needed not to make application crash when releasing the window in our destructor + // (I prefer to take control of everything :P) + [[self window] setReleasedWhenClosed:NO]; + [[self window] setAcceptsMouseMovedEvents:YES]; + + if ([self isFullscreen]) { + myFullscreenMode = aMode; + + // Using this because full screen window was not always + // in front of the other application windows when unhiding app + [[self window] setLevel:NSFloatingWindowLevel]; + } + } + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] + removeObserver:self + name:NSWindowDidMoveNotification + object:[self window]]; + [super dealloc]; +} + +//////////////////////////////////////////////////////////// +/// Sets the window's fullscreen state +//////////////////////////////////////////////////////////// +- (void)setFullscreen:(BOOL)aFlag +{ + myIsFullscreen = aFlag; +} + +//////////////////////////////////////////////////////////// +/// Returns the window's fullscreen state +//////////////////////////////////////////////////////////// +- (BOOL)isFullscreen +{ + return myIsFullscreen; +} + //////////////////////////////////////////////////////////// /// Notification method receiver when the window finish moving //////////////////////////////////////////////////////////// @@ -858,5 +922,176 @@ [sender center]; } +//////////////////////////////////////////////////////////// +/// Close or open the window +//////////////////////////////////////////////////////////// +- (void)show:(bool)flag +{ + NSAssert([self window] != nil, @"expected valid window"); + + if (flag && ![[self window] isVisible]) { + // Wanna open the closed window + + if ([self isFullscreen]) { + [[sfPrivAppController sharedController] + setFullscreenWindow:self + mode:&myFullscreenMode]; + } else { + // Show the window + [[self window] makeKeyAndOrderFront:nil]; + } + } else if (!flag && [[self window] isVisible]) { + // Wanna close the opened window + + if ([self isFullscreen]) { + [[sfPrivAppController sharedController] + setFullscreenWindow:nil + mode:NULL]; + } else { + // Close the window + [[self window] close]; + } + } +} + +//////////////////////////////////////////////////////////// +/// Forward call to set the window position on screen +//////////////////////////////////////////////////////////// +- (void)setPosition:(NSPoint)aPosition +{ + if (![self isFullscreen]) { + [super setPosition:aPosition]; + } +} + +//////////////////////////////////////////////////////////// +/// Forward call to set the window size +//////////////////////////////////////////////////////////// +- (void)setSize:(NSSize)size +{ + if (![self isFullscreen]) { + [super setSize:size]; + } +} + +@end + + +@implementation sfPrivImportedWindow + +- (id)initWithWindow:(NSWindow *)aWindow + settings:(sf::WindowSettings&)someSettings +{ + self = [super init]; + + if (self) { + [self setWindow:aWindow]; + + // Make the OpenGL view + sf::VideoMode mode([[[self window] contentView] frame].size.width, + [[[self window] contentView] frame].size.height); + GLView *newView = [[GLView alloc] + initWithFrame:[[[self window] contentView] frame] + mode:mode + settings:someSettings]; + + if (!newView) { + std::cerr << "Unable to create the OpenGL view" << std::endl; + [self autorelease]; + return nil; + } + + [self putOpenGLView:[newView autorelease]]; + } + + return self; +} + +@end + + +@implementation sfPrivImportedView + + +- (id)initWithView:(NSView *)aView + settings:(sf::WindowSettings&)someSettings +{ + self = [super init]; + if (self) + { + parentView = [aView retain]; + [self setWindow:[parentView window]]; + + // Make the OpenGL view + sf::VideoMode mode([parentView bounds].size.width, + [parentView bounds].size.height); + GLView *newView = [[GLView alloc] + initWithFrame:[parentView bounds] + mode:mode + settings:someSettings]; + + if (!newView) { + std::cerr << "Unable to create the OpenGL view" << std::endl; + [self autorelease]; + return nil; + } + + [self putOpenGLView:[newView autorelease]]; + + } + return self; +} + +- (void)dealloc +{ + [parentView release]; + [super dealloc]; +} + +//////////////////////////////////////////////////////////// +/// Registers the the OpenGL view and adds it to its parent container +//////////////////////////////////////////////////////////// +- (void)putOpenGLView:(GLView *)aView +{ + [self setView:aView]; + + // Finish setting up the view and window + NSRect originalFrame = [[self window] frame]; + NSRect tmpFrame = originalFrame; + originalFrame.origin.x++; + + [[self window] setFrame:tmpFrame display:YES]; + [[self window] setFrame:originalFrame display:YES]; + + + // Add the view to our *parent view* and tell it to the view + [parentView addSubview:[self view]]; + [[self view] finishInitialization]; +} + +//////////////////////////////////////////////////////////// +/// Forward call to set the window position on screen +//////////////////////////////////////////////////////////// +- (void)setPosition:(NSPoint)aPosition +{ + std::cerr + << "Warning: called Window::SetPosition() on a window imported from a widget. " + << "This method has been disabled in this case and has no effect. " + << "Directly use the widget if you want to move it." + << std::endl; +} + +//////////////////////////////////////////////////////////// +/// Forward call to set the window size +//////////////////////////////////////////////////////////// +- (void)setSize:(NSSize)size +{ + std::cerr + << "Warning: called Window::SetSize() on a window imported from a widget. " + << "This method has been disabled in this case and has no effect. " + << "Directly use the widget if you want to resize it." + << std::endl; +} + @end diff --git a/src/SFML/Window/Cocoa/WindowImplCocoa.hpp b/src/SFML/Window/Cocoa/WindowImplCocoa.hpp index 25bef322d..62158f0f1 100644 --- a/src/SFML/Window/Cocoa/WindowImplCocoa.hpp +++ b/src/SFML/Window/Cocoa/WindowImplCocoa.hpp @@ -33,10 +33,10 @@ #include #ifdef __OBJC__ -@class WindowWrapper; -typedef WindowWrapper* WindowWrapperRef; +@class sfPrivWindow; +typedef sfPrivWindow* sfPrivWindowRef; #else -typedef void* WindowWrapperRef; +typedef void* sfPrivWindowRef; #endif namespace sf @@ -192,7 +192,7 @@ private : //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - WindowWrapperRef myWrapper; + sfPrivWindowRef myWrapper; bool myUseKeyRepeat; bool myMouseIn; float myWheelStatus; diff --git a/src/SFML/Window/Cocoa/WindowImplCocoa.mm b/src/SFML/Window/Cocoa/WindowImplCocoa.mm index b1fe2204c..9fc71dc27 100644 --- a/src/SFML/Window/Cocoa/WindowImplCocoa.mm +++ b/src/SFML/Window/Cocoa/WindowImplCocoa.mm @@ -67,7 +67,7 @@ myUseKeyRepeat(false), myMouseIn(false), myWheelStatus(0.0f) { - [AppController sharedController]; + [sfPrivAppController sharedController]; // Create the shared OpenGL context if ([GLContext sharedContext]) { @@ -88,22 +88,19 @@ myUseKeyRepeat(false), myMouseIn(false), myWheelStatus(0.0f) { - if (Handle) - { - NSWindow *cocoaWindow = nil; - + if (Handle) { // Classical window import - if ([(id)Handle isKindOfClass:[NSWindow class]]) - { - cocoaWindow = (NSWindow *)Handle; + if ([(id)Handle isKindOfClass:[NSWindow class]]) { + myWrapper = [[sfPrivImportedWindow alloc] + initWithWindow:(NSWindow *)Handle + settings:params]; } // Qt "window" import - else if ([(id)Handle isKindOfClass:[NSView class]]) - { - cocoaWindow = [(NSView *)Handle window]; - } - else - { + else if ([(id)Handle isKindOfClass:[NSView class]]) { + myWrapper = [[sfPrivImportedView alloc] + initWithView:(NSView *)Handle + settings:params]; + } else { std::cerr << "Cannot import this Window Handle because it is neither" << "a nor object" @@ -114,36 +111,23 @@ myWheelStatus(0.0f) } - if (cocoaWindow) - { + if (myWrapper) { + [myWrapper setDelegate:this]; - // We create the window according to the given handle - myWrapper = [[WindowWrapper alloc] initWithWindow:cocoaWindow - settings:params - delegate:this]; + // initial mouse state + myMouseIn = [myWrapper mouseInside]; - if (myWrapper) - { - // initial mouse state - myMouseIn = [myWrapper mouseInside]; - - // We set the myWidth and myHeight members to the correct values - myWidth = (int) [[myWrapper glView] frame].size.width; - myHeight = (int) [[myWrapper glView] frame].size.height; - } else { - std::cerr << "Failed to make the public window" << std::endl; - } + // We set the myWidth and myHeight members to the correct values + myWidth = (int) [[myWrapper view] frame].size.width; + myHeight = (int) [[myWrapper view] frame].size.height; + } else { + std::cerr << "Failed to make the public window" << std::endl; } - else - { - std::cerr - << "Could not get a valid NSWindow object from the given handle" - << " (%p <" - << [[(id)Handle className] UTF8String] - << ">" - << std::endl; - } - + } else { + std::cerr + << "Invalid null handle given to " + << "Window::Window(WindowHandle Handle, const WindowSettings& Params)" + << std::endl; } } @@ -163,14 +147,18 @@ myWheelStatus(0.0f) encoding:NSASCIIStringEncoding]; // We create the window - myWrapper = [[WindowWrapper alloc] initWithSettings:params - videoMode:Mode - style:WindowStyle - title:title - delegate:this]; + myWrapper = [[sfPrivOwnedWindow alloc] + initWithVideoMode:Mode + settings:params + style:WindowStyle + title:title]; + + if (myWrapper) { + [myWrapper setDelegate:this]; + // initial mouse state myMouseIn = [myWrapper mouseInside]; @@ -566,7 +554,7 @@ void WindowImplCocoa::Display() void WindowImplCocoa::ProcessEvents() { // Forward event handling call to the application controller - [[AppController sharedController] processEvents]; + [[sfPrivAppController sharedController] processEvents]; } @@ -626,7 +614,7 @@ void WindowImplCocoa::SetCursorPosition(unsigned int Left, unsigned int Top) pos.y = [[myWrapper window] frame].size.height - pos.y; // Adjust for view reference instead of window - pos.y -= [[myWrapper window] frame].size.height - [[myWrapper glView] frame].size.height; + pos.y -= [[myWrapper window] frame].size.height - [[myWrapper view] frame].size.height; // Convert to screen coordinates NSPoint absolute = [[myWrapper window] convertBaseToScreen:pos]; @@ -635,7 +623,8 @@ void WindowImplCocoa::SetCursorPosition(unsigned int Left, unsigned int Top) absolute.y = [[NSScreen mainScreen] frame].size.height - absolute.y; // Move cursor - CGDisplayMoveCursorToPoint([AppController primaryScreen], CGPointMake(absolute.x, absolute.y)); + CGDisplayMoveCursorToPoint([sfPrivAppController primaryScreen], + CGPointMake(absolute.x, absolute.y)); } }