From e42882d2ca24cfb1b816d0da82a68a1454cbead3 Mon Sep 17 00:00:00 2001 From: ceylo Date: Sat, 14 Mar 2009 13:49:54 +0000 Subject: [PATCH] Switching to Cocoa implementation way. Updated copyright year. Removed WindowController. Added Cocoa window import support. git-svn-id: https://sfml.svn.sourceforge.net/svnroot/sfml/trunk@1049 4e206d99-4929-0410-ac5d-dfc041789085 --- src/SFML/Window/Cocoa/AppController.h | 78 +- src/SFML/Window/Cocoa/AppController.mm | 469 +++++----- src/SFML/Window/Cocoa/GLKit.h | 216 +++++ src/SFML/Window/Cocoa/GLKit.mm | 1017 +++++++++++++++++++++ src/SFML/Window/Cocoa/WindowImplCocoa.hpp | 64 +- src/SFML/Window/Cocoa/WindowImplCocoa.mm | 1011 ++++---------------- 6 files changed, 1679 insertions(+), 1176 deletions(-) create mode 100644 src/SFML/Window/Cocoa/GLKit.h create mode 100644 src/SFML/Window/Cocoa/GLKit.mm diff --git a/src/SFML/Window/Cocoa/AppController.h b/src/SFML/Window/Cocoa/AppController.h index 365afc9d3..f56db4eb5 100644 --- a/src/SFML/Window/Cocoa/AppController.h +++ b/src/SFML/Window/Cocoa/AppController.h @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2008 Lucas Soltic (elmerod@gmail.com) and Laurent Gomila (laurent.gom@gmail.com) +// Copyright (C) 2007-2009 Lucas Soltic (ceylow@gmail.com) and Laurent Gomila (laurent.gom@gmail.com) // // This software is provided 'as-is', without any express or implied warranty. // In no event will the authors be held liable for any damages arising from the use of this software. @@ -26,12 +26,8 @@ //////////////////////////////////////////////////////////// // Headers //////////////////////////////////////////////////////////// -#import #import -#import #import -#import -#import #define SharedAppController [AppController sharedController] @@ -42,80 +38,50 @@ enum { CleanScreen }; - +@class WindowWrapper; @interface AppController : NSObject { - // Note: objc allocation doesn't call C++ constructor - std::vector *windows; - - NSAutoreleasePool *mainPool; - sf::Clock *cleaner; - sf::VideoMode desktopMode; - sf::VideoMode prevMode; + BOOL myOwningEventLoop; + WindowWrapper *myFullscreenWrapper; + NSAutoreleasePool *myMainPool; + sf::VideoMode myDesktopMode; + sf::VideoMode myPrevMode; } //////////////////////////////////////////////////////////// -/// Return the shared AppController object. Makes one if needed +/// Return the shared AppController instance. Make one if needed. //////////////////////////////////////////////////////////// + (AppController *)sharedController; //////////////////////////////////////////////////////////// -/// Reallocate main pool to release autoreleased objects -//////////////////////////////////////////////////////////// -- (void)resetPool; - -//////////////////////////////////////////////////////////// -/// Register our application and launch it if needed -//////////////////////////////////////////////////////////// -- (void)runApplication; - -//////////////////////////////////////////////////////////// -/// Terminate the current running application -//////////////////////////////////////////////////////////// -- (void)quitApplication:(id)sender; - -//////////////////////////////////////////////////////////// -/// Make menu bar +/// Make the menu bar //////////////////////////////////////////////////////////// - (void)makeMenuBar; //////////////////////////////////////////////////////////// -/// Get the events and put them into an array for each window +/// Process all the events and send them to the application +/// No event is processed if the AppController instance is +/// not the owner of the event loop (ie: user made his own loop) //////////////////////////////////////////////////////////// - (void)processEvents; //////////////////////////////////////////////////////////// -/// Add the 'windowImplObj' object to the list of known windows +/// Set @window as the current fullscreen window +/// Change the screen resolution if needed according to @window and @fullscreenMode //////////////////////////////////////////////////////////// -- (void)registerWindow:(sf::priv::WindowImplCocoa *)windowImplObj; - -//////////////////////////////////////////////////////////// -/// Remove the 'windowImplObj' object from the list of known windows -//////////////////////////////////////////////////////////// -- (void)unregisterWindow:(sf::priv::WindowImplCocoa *)windowImplObj; - -//////////////////////////////////////////////////////////// -/// Return true is one of the registered window is a full screen one -//////////////////////////////////////////////////////////// -- (bool)isUsingFullscreen; +- (void)setFullscreenWindow:(WindowWrapper *)window mode:(sf::VideoMode *)fullscreenMode; //////////////////////////////////////////////////////////// /// Perform fade operation where 'operation' is one of { FillScreen, CleanScreen} /// and 'time' is the time during which you wish the operation to be performed. /// Set 'sync' to true if you do not want the method to end before the end -/// of the fade operation. Pass the last used token or a new one if you are -/// using this method for the first time. This lets the method release some -/// resources when doing CleanScreen operation. +/// of the fade operation. //////////////////////////////////////////////////////////// -- (void)doFadeOperation:(int)operation time:(float)time sync:(bool)sync token:(CGDisplayFadeReservationToken *)prevToken; +- (void)doFadeOperation:(int)operation time:(float)time sync:(bool)sync; + +//////////////////////////////////////////////////////////// +/// Return the desktop video mode (made at the instance initialization) +//////////////////////////////////////////////////////////// +- (const sf::VideoMode&)desktopMode; @end - -//////////////////////////////////////////////////////////// -/// check that ptr is valid, otherwise print msg in -/// std::cerr and throw std::bad_alloc. -/// Must be used to check alloc results -//////////////////////////////////////////////////////////// -template -T *massert(T *ptr); - diff --git a/src/SFML/Window/Cocoa/AppController.mm b/src/SFML/Window/Cocoa/AppController.mm index a6b7310f5..3dced29d1 100644 --- a/src/SFML/Window/Cocoa/AppController.mm +++ b/src/SFML/Window/Cocoa/AppController.mm @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2008 Lucas Soltic (elmerod@gmail.com) and Laurent Gomila (laurent.gom@gmail.com) +// Copyright (C) 2007-2009 Lucas Soltic (ceylow@gmail.com) and Laurent Gomila (laurent.gom@gmail.com) // // This software is provided 'as-is', without any express or implied warranty. // In no event will the authors be held liable for any damages arising from the use of this software. @@ -27,14 +27,13 @@ // Headers //////////////////////////////////////////////////////////// #import -#import -#import +#import #import #import #import -// AppController singleton +// AppController singleton object static AppController *shared = nil; @@ -61,160 +60,120 @@ static AppController *shared = nil; @implementation AppController + +//////////////////////////////////////////////////////////// +/// Return an initialized AppController instance +/// Save the desktop mode +/// Make the main autorelease pool +/// Set the application observer +//////////////////////////////////////////////////////////// - (id)init { self = [super init]; if (self != nil) { - windows = new std::vector ; - cleaner = new sf::Clock; + myOwningEventLoop = NO; + + // Save the desktop mode + myDesktopMode = sf::VideoMode::GetDesktopMode(); + myPrevMode = myDesktopMode; + + // Make the app autorelease pool + myMainPool = [[NSAutoreleasePool alloc] init]; + + // Don't go on if the user handles the app + if (![NSApp isRunning]) + { + // Force our application to appear in the Dock and make it able + // to get focus (even when it's a raw executable) + ProcessSerialNumber psn; + + if (!GetCurrentProcess(&psn)) { + TransformProcessType(&psn, kProcessTransformToForegroundApplication); + SetFrontProcess(&psn); + } + + // Make the app + [NSApplication sharedApplication]; + + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + // I want to go back to the desktop mode + // if we've a fullscreen window when hiding + [nc addObserver:self + selector:@selector(applicationWillHide:) + name:NSApplicationWillHideNotification + object:NSApp]; + + // And restore de fullscreen mode when unhiding + [nc addObserver:self + selector:@selector(applicationWillUnhide:) + name:NSApplicationWillUnhideNotification + object:NSApp]; + + // Go back to desktop mode before exit + [nc addObserver:self + selector:@selector(applicationWillTerminate:) + name:NSApplicationWillTerminateNotification + object:NSApp]; + + if ([NSApp mainMenu] == nil) { + [self makeMenuBar]; + } + } } return self; } +//////////////////////////////////////////////////////////// +/// Clean the controller +//////////////////////////////////////////////////////////// - (void)dealloc { - delete windows; - delete cleaner; + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [myFullscreenWrapper release]; [super dealloc]; } //////////////////////////////////////////////////////////// -/// Return the shared AppController object. Makes one if needed +/// Return the shared AppController instance. Make one if needed. //////////////////////////////////////////////////////////// + (AppController *)sharedController { - if (nil == shared) { - shared = [massert([AppController alloc]) init]; - } + if (nil == shared) + shared = [[AppController alloc] init]; return shared; } //////////////////////////////////////////////////////////// -/// Reallocate main pool to release autoreleased objects -//////////////////////////////////////////////////////////// -- (void)resetPool -{ - [mainPool release]; - - mainPool = [massert([NSAutoreleasePool alloc]) init]; -} - - -//////////////////////////////////////////////////////////// -/// Register our application and launch it if needed -//////////////////////////////////////////////////////////// -- (void)runApplication -{ - if ([NSApp isRunning]) - return; - - // We want our application to appear in the Dock and be able - // to get focus - ProcessSerialNumber psn; - - if (!GetCurrentProcess(&psn)) { - TransformProcessType(&psn, kProcessTransformToForegroundApplication); - SetFrontProcess(&psn); - } - - if (NSApp == nil) { - massert([NSApplication sharedApplication]); - } - - if ([NSApp mainMenu] == nil) { - [self makeMenuBar]; - } - - [NSApp finishLaunching]; - [NSApp setRunning:YES]; - [NSApp setDelegate:self]; - - desktopMode = sf::VideoMode::GetDesktopMode(); -} - - -//////////////////////////////////////////////////////////// -/// Terminate the current running application -//////////////////////////////////////////////////////////// -- (void)quitApplication:(id)sender -{ - // Close all windows - // SFML user has to detect when all windows are closed - NSWindow *current = nil; - sf::priv::WindowImplCocoa *priv = NULL; - - while (windows->size()) { - priv = windows->at(0); - current = static_cast (priv->CocoaWindow()); - [current close]; - windows->erase(windows->begin()); - } -} - - -//////////////////////////////////////////////////////////// -/// Returns the first full screen window found or nil -//////////////////////////////////////////////////////////// -- (SFWindow *)fullscreenWindow -{ - SFWindow *window = nil; - std::vector::size_type sz = windows->size(); - std::vector::size_type idx; - - for (idx = 0; idx < sz; idx++) { - sf::priv::WindowImplCocoa *win = windows->at(idx); - if (win && win->IsFullscreen()) { - window = static_cast (win->CocoaWindow()); - break; - } - } - - return window; -} - - -//////////////////////////////////////////////////////////// -/// Hide all the fullscreen windows and switch to desktop display mode +/// Hide all the fullscreen windows and switch back to the desktop display mode //////////////////////////////////////////////////////////// - (void)applicationWillHide:(NSNotification *)aNotification { - if ([self isUsingFullscreen]) { - prevMode = sf::VideoMode::GetDesktopMode(); + if (myFullscreenWrapper) { + myPrevMode = sf::VideoMode::GetDesktopMode(); CFDictionaryRef displayMode = CGDisplayBestModeForParameters (kCGDirectMainDisplay, - desktopMode.BitsPerPixel, - desktopMode.Width, - desktopMode.Height, + myDesktopMode.BitsPerPixel, + myDesktopMode.Width, + myDesktopMode.Height, NULL); - CGDisplayFadeReservationToken token = kCGDisplayFadeReservationInvalidToken; - // Fade to black screen - [SharedAppController doFadeOperation:FillScreen time:0.2f sync:true token:&token]; + [self doFadeOperation:FillScreen time:0.2f sync:true]; - // Make all the full screen SFML windows unvisible - std::vector::size_type sz = windows->size(); - std::vector::size_type idx; - - for (idx = 0; idx < sz; idx++) { - sf::priv::WindowImplCocoa *win = windows->at(idx); - - if (win->IsFullscreen()) { - [static_cast (win->CocoaWindow()) setAlphaValue:0.0f]; - } - } + // Make the full screen window unvisible + [[myFullscreenWrapper window] setAlphaValue:0.0f]; // Switch to the wished display mode CGDisplaySwitchToMode(kCGDirectMainDisplay, displayMode); // Fade to normal screen - [SharedAppController doFadeOperation:CleanScreen time:0.5f sync:false token:&token]; + [self doFadeOperation:CleanScreen time:0.5f sync:false]; } } @@ -224,41 +183,43 @@ static AppController *shared = nil; //////////////////////////////////////////////////////////// - (void)applicationWillUnhide:(NSNotification *)aNotification { - if ([self isUsingFullscreen]) { + if (myFullscreenWrapper) { CFDictionaryRef displayMode = CGDisplayBestModeForParameters (kCGDirectMainDisplay, - prevMode.BitsPerPixel, - prevMode.Width, - prevMode.Height, + myPrevMode.BitsPerPixel, + myPrevMode.Width, + myPrevMode.Height, NULL); - CGDisplayFadeReservationToken token = kCGDisplayFadeReservationInvalidToken; - // Fade to a black screen - [SharedAppController doFadeOperation:FillScreen time:0.5f sync:true token:&token]; + [self doFadeOperation:FillScreen time:0.5f sync:true]; [NSMenu setMenuBarVisible:NO]; // Switch to the wished display mode CGDisplaySwitchToMode(kCGDirectMainDisplay, displayMode); - // Make all the SFML windows visible - std::vector::size_type sz = windows->size(); - std::vector::size_type idx; - - for (idx = 0; idx < sz; idx++) { - sf::priv::WindowImplCocoa *win = windows->at(idx); - - if (win->IsFullscreen()) { - [static_cast (win->CocoaWindow()) setAlphaValue:1.0f]; - [static_cast (win->CocoaWindow()) center]; - } + // Show the fullscreen window if existing + if (myFullscreenWrapper) + { + [[myFullscreenWrapper window] setAlphaValue:1.0f]; + [[myFullscreenWrapper window] center]; } // Fade to normal screen - [SharedAppController doFadeOperation:CleanScreen time:0.5f sync:false token:&token]; + [self doFadeOperation:CleanScreen time:0.5f sync:false]; } } +- (void)applicationWillTerminate:(NSNotification *)aNotification +{ + if (myFullscreenWrapper) + [self setFullscreenWindow:nil mode:NULL]; + + // FIXME: should I really do this ? what about the user owned windows ? + // And is this really useful as the application is about to exit ? + [NSApp makeWindowsPerform:@selector(close) inOrder:NO]; +} + //////////////////////////////////////////////////////////// /// Make menu bar //////////////////////////////////////////////////////////// @@ -282,10 +243,10 @@ static AppController *shared = nil; // Create the main menu bar - [NSApp setMainMenu:[massert([NSMenu alloc]) init]]; + [NSApp setMainMenu:[[NSMenu alloc] init]]; // Create the application menu - appleMenu = [massert([NSMenu alloc]) initWithTitle:@""]; + appleMenu = [[NSMenu alloc] initWithTitle:@""]; // Put menu items // + 'About' menu item @@ -317,15 +278,15 @@ static AppController *shared = nil; // + 'Quit' menu item title = [@"Quit " stringByAppendingString:appName]; - quitMenuItem = [[massert([NSMenuItem alloc]) + quitMenuItem = [[[NSMenuItem alloc] initWithTitle:title - action:@selector(quitApplication:) + action:@selector(terminate:) keyEquivalent:@"q"] autorelease]; - [quitMenuItem setTarget:self]; + //[quitMenuItem setTarget:self]; [appleMenu addItem:quitMenuItem]; // Put the menu into the menubar - menuItem = [massert([NSMenuItem alloc]) + menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; @@ -338,11 +299,11 @@ static AppController *shared = nil; [appleMenu release]; // 'File' menu - fileMenu = [massert([NSMenu alloc]) + fileMenu = [[NSMenu alloc] initWithTitle:@"File"]; // + 'Close' menu item - menuItem = [massert([NSMenuItem alloc]) + menuItem = [[NSMenuItem alloc] initWithTitle:@"Close" action:@selector(performClose:) keyEquivalent:@"w"]; @@ -350,7 +311,7 @@ static AppController *shared = nil; [menuItem release]; // + 'File' menu item (head) - menuItem = [massert([NSMenuItem alloc]) + menuItem = [[NSMenuItem alloc] initWithTitle:@"File" action:nil keyEquivalent:@""]; @@ -359,11 +320,11 @@ static AppController *shared = nil; [menuItem release]; // 'Window' menu - windowMenu = [massert([NSMenu alloc]) + windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; // + 'Minimize' menu item - menuItem = [massert([NSMenuItem alloc]) + menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; @@ -371,7 +332,7 @@ static AppController *shared = nil; [menuItem release]; // + 'Window' menu item (head) - menuItem = [massert([NSMenuItem alloc]) + menuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; [menuItem setSubmenu:windowMenu]; @@ -385,127 +346,109 @@ static AppController *shared = nil; //////////////////////////////////////////////////////////// -/// Delegate method in order to prevent usual -terminate: -//////////////////////////////////////////////////////////// -- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender -{ - [self quitApplication:nil]; - return NSTerminateCancel; -} - - -//////////////////////////////////////////////////////////// -/// Get the events and put them into an array for each window +/// Process all the events and send them to the application +/// No event is processed if the AppController instance is +/// not the owner of the event loop (ie: user made his own loop) //////////////////////////////////////////////////////////// - (void)processEvents { - // Release the main autorelease pool every second - if (cleaner->GetElapsedTime() > 1.0f) { - cleaner->Reset(); - [self resetPool]; + // Check there is a run loop + if (![NSApp isRunning]) + { + // Get the ownershipt of event handling if not and run + [NSApp finishLaunching]; + [NSApp setRunning:YES]; + myOwningEventLoop = YES; } + // Clean the autorelease pool + [myMainPool release]; + myMainPool = [[NSAutoreleasePool alloc] init]; + NSEvent *event = nil; - while (nil != (event = [NSApp nextEventMatchingMask:NSAnyEventMask - untilDate:nil - inMode:NSEventTrackingRunLoopMode - dequeue:YES])) { - NSWindow *keyWindow = [NSApp keyWindow]; - - if (keyWindow == nil) { - // Is there a fullscreen WindowImpl object ? + if (myOwningEventLoop) + { + // Minimal event loop + while (nil != (event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:nil + inMode:NSEventTrackingRunLoopMode + dequeue:YES])) + { [NSApp sendEvent:event]; - } else { - - std::vector::size_type cnt = windows->size(); - std::vector::size_type idx; - - // is the key window a SFML window ? - for (idx = 0;idx < cnt; idx++) { - sf::priv::WindowImplCocoa *ptr = windows->at(idx);; - - if (ptr->CocoaWindow() == keyWindow) { - // yup, it is - ptr->HandleEvent(static_cast (event)); - break; - } - } - - // nop, it isn't - if (idx == cnt) { - [NSApp sendEvent:event]; - } } } } //////////////////////////////////////////////////////////// -/// Add the 'windowImplObj' object to the list of known windows +/// Set @window as the current fullscreen window +/// Change the screen resolution if needed according to @window and @fullscreenMode //////////////////////////////////////////////////////////// -- (void)registerWindow:(sf::priv::WindowImplCocoa *)windowImplObj +- (void)setFullscreenWindow:(WindowWrapper *)aWrapper mode:(sf::VideoMode *)fullscreenMode { - - if (windowImplObj != NULL) { - std::vector::size_type sz = windows->size(); - std::vector::size_type idx; + // If we have a fullscreen window and want to remove it + if (myFullscreenWrapper && aWrapper == nil) + { + // Get the CoreGraphics display mode according to the desktop mode + CFDictionaryRef displayMode = CGDisplayBestModeForParameters (kCGDirectMainDisplay, + myDesktopMode.BitsPerPixel, + myDesktopMode.Width, + myDesktopMode.Height, + NULL); - for (idx = 0; idx < sz; idx++) { - if (windows->at(idx) == windowImplObj) { - break; - } - } + // Fade to black screen + [self doFadeOperation:FillScreen time:0.2f sync:true]; + // Switch to the desktop display mode + CGDisplaySwitchToMode(kCGDirectMainDisplay, displayMode); - // Register window only if not already registered - if (sz == idx) { - windows->push_back(windowImplObj); - } + // Close the window + [[myFullscreenWrapper window] close]; + + // Show the menu bar + [NSMenu setMenuBarVisible:YES]; + + // Fade to normal screen + [self doFadeOperation:CleanScreen time:0.5f sync:true]; + + // Release the saved window wrapper + [myFullscreenWrapper release], myFullscreenWrapper = nil; } -} - - -//////////////////////////////////////////////////////////// -/// Remove the 'windowImplObj' object from the list of known windows -//////////////////////////////////////////////////////////// -- (void)unregisterWindow:(sf::priv::WindowImplCocoa *)windowImplObj -{ - if (windowImplObj != NULL) { - std::vector::size_type sz = windows->size(); - std::vector::size_type idx; + else if (myFullscreenWrapper == nil && aWrapper) + { + assert(fullscreenMode != NULL); - for (idx = 0; idx < sz; idx++) { - if (windows->at(idx) == windowImplObj) { - break; - } - } + // Get the CoreGraphics display mode according to the given sf mode + CFDictionaryRef displayMode = CGDisplayBestModeForParameters (kCGDirectMainDisplay, + fullscreenMode->BitsPerPixel, + fullscreenMode->Width, + fullscreenMode->Height, + NULL); - if (idx < sz) { - windows->erase(windows->begin() + idx); - } + // Fade to a black screen + [self doFadeOperation:FillScreen time:0.5f sync:true]; + + // Hide to the main menu bar + [NSMenu setMenuBarVisible:NO]; + + // Switch to the wished display mode + CGDisplaySwitchToMode(kCGDirectMainDisplay, displayMode); + + // Open and center the window + [[aWrapper window] makeKeyAndOrderFront:nil]; + [[aWrapper window] center]; + + // Fade to normal screen + [self doFadeOperation:CleanScreen time:0.2f sync:false]; + + // Save the fullscreen wrapper + myFullscreenWrapper = [aWrapper retain]; } -} - - -//////////////////////////////////////////////////////////// -/// Return true is one of the registered window is a full screen one -//////////////////////////////////////////////////////////// -- (bool)isUsingFullscreen -{ - bool isUsing = false; - std::vector::size_type sz = windows->size(); - std::vector::size_type idx; - - for (idx = 0; idx < sz; idx++) { - sf::priv::WindowImplCocoa *win = windows->at(idx); - if (win && win->IsFullscreen()) { - isUsing = true; - break; - } + else + { + std::cerr << "Inconcistency error for arguments given to -[AppController setFullscreenWindow:mode:]" << std::endl; } - - return isUsing; } @@ -517,11 +460,10 @@ static AppController *shared = nil; /// using this method for the first time. This lets the method release some /// resources when doing CleanScreen operation. //////////////////////////////////////////////////////////// -- (void) doFadeOperation:(int)operation time:(float)time sync:(bool)sync token:(CGDisplayFadeReservationToken *)prevToken +- (void) doFadeOperation:(int)operation time:(float)time sync:(bool)sync { - CGDisplayFadeReservationToken token = kCGDisplayFadeReservationInvalidToken; - if (prevToken) - token = *prevToken; + static CGDisplayFadeReservationToken prevToken = kCGDisplayFadeReservationInvalidToken; + CGDisplayFadeReservationToken token = prevToken; CGError result = 0, capture = 0; @@ -539,7 +481,7 @@ static AppController *shared = nil; CGDisplayFade(token, time, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, - 0.0, 0.0, 0.0, sync); + 0.0f, 0.0f, 0.0f, sync); // Now, release the non black-filling capture CGDisplayRelease(kCGDirectMainDisplay); @@ -549,8 +491,7 @@ static AppController *shared = nil; CGDisplayCaptureWithOptions(kCGDirectMainDisplay, kCGCaptureNoOptions); } - if (prevToken) - *prevToken = token; + prevToken = token; } } else if (operation == CleanScreen) { // Get access for the fade operation @@ -569,14 +510,13 @@ static AppController *shared = nil; CGDisplayFade(token, time, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, - 0.0, 0.0, 0.0, sync); + 0.0f, 0.0f, 0.0f, sync); // Release the fade operation token CGReleaseDisplayFadeReservation(token); // Invalidate the given token - if (prevToken) - *prevToken = kCGDisplayFadeReservationInvalidToken; + prevToken = kCGDisplayFadeReservationInvalidToken; } // Release the captured display @@ -585,15 +525,14 @@ static AppController *shared = nil; } } + +//////////////////////////////////////////////////////////// +/// Return the desktop video mode (made at the instance initialization) +//////////////////////////////////////////////////////////// +- (const sf::VideoMode&)desktopMode +{ + return myDesktopMode; +} + @end - -template -T *massert(T *ptr) -{ - if (NULL == ptr) { - throw std::bad_alloc(); - } - - return ptr; -} diff --git a/src/SFML/Window/Cocoa/GLKit.h b/src/SFML/Window/Cocoa/GLKit.h new file mode 100644 index 000000000..aa2125c48 --- /dev/null +++ b/src/SFML/Window/Cocoa/GLKit.h @@ -0,0 +1,216 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Lucas Soltic (ceylow@gmail.com) and Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#import +#import + + +//////////////////////////////////////////////////////////// +/// Window independant OpenGL context class +//////////////////////////////////////////////////////////// +@interface GLContext : NSOpenGLContext +{ + GLContext *mySharedContext; +} + +//////////////////////////////////////////////////////////// +/// Return the shared OpenGL context instance (making one if needed) +//////////////////////////////////////////////////////////// ++ (id)sharedContext; + +//////////////////////////////////////////////////////////// +/// Make a new OpenGL context according to the @attribs settings +/// and the shared context @context +//////////////////////////////////////////////////////////// +- (id)initWithAttributes:(sf::WindowSettings&)attribs + sharedContext:(GLContext *)context; + +@end + + +//////////////////////////////////////////////////////////// +/// Customized Cocoa OpenGL view +//////////////////////////////////////////////////////////// +@interface GLView : NSOpenGLView +{ + sf::priv::WindowImplCocoa *myDelegate; + GLContext *myGLContext; +} + +//////////////////////////////////////////////////////////// +/// 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; + +//////////////////////////////////////////////////////////// +/// Finish view setting (after having added it to the window) +//////////////////////////////////////////////////////////// +- (void)finishInitialization; + +//////////////////////////////////////////////////////////// +/// Forward call to en/disable vertical synchronization +//////////////////////////////////////////////////////////// +- (void)enableVerticalSync:(bool)flag; + +//////////////////////////////////////////////////////////// +/// Forward call to set the OpenGL context as active according to @flag +//////////////////////////////////////////////////////////// +- (void)setActive:(bool)flag; + +//////////////////////////////////////////////////////////// +/// Forward call to flush the OpenGL context +//////////////////////////////////////////////////////////// +- (void)flushBuffer; + +@end + +//////////////////////////////////////////////////////////// +/// Cocoa window implementation to let fullscreen windows +/// catch key events +//////////////////////////////////////////////////////////// +@interface GLWindow : NSWindow + +//////////////////////////////////////////////////////////// +/// Technical note: this class must neither contain new members +/// nor methods. It is used transparently as a NSWindow object +/// by WindowWrapper. Not following this rule could result +/// in a segmentation fault or data corruption. +//////////////////////////////////////////////////////////// + +@end + +//////////////////////////////////////////////////////////// +/// WindowWrapper class : handles both imported and self-built windows +//////////////////////////////////////////////////////////// +@interface WindowWrapper : NSObject +{ + GLWindow *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; + + +//////////////////////////////////////////////////////////// +/// Finish the window setup (without knowing whether it's a imported +/// window) +//////////////////////////////////////////////////////////// +/* - (void)setupGLViewAndWindow; */ + +//////////////////////////////////////////////////////////// +/// Return a reference to the internal Cocoa window +//////////////////////////////////////////////////////////// +- (NSWindow *)window; + +//////////////////////////////////////////////////////////// +/// Return a reference to the internal Cocoa OpenGL view +//////////////////////////////////////////////////////////// +- (GLView *)glView; + +//////////////////////////////////////////////////////////// +/// Forward call to set the window position on screen +//////////////////////////////////////////////////////////// +- (void)setPosition:(NSPoint)pos; + +//////////////////////////////////////////////////////////// +/// Forward call to set the window size +//////////////////////////////////////////////////////////// +- (void)setSize:(NSSize)size; + +//////////////////////////////////////////////////////////// +/// Return the mouse location relative to the internal window +//////////////////////////////////////////////////////////// +- (NSPoint)mouseLocation; + +//////////////////////////////////////////////////////////// +/// Return whether the mouse is on our window +//////////////////////////////////////////////////////////// +- (BOOL)mouseInside; + +//////////////////////////////////////////////////////////// +/// Close or open the window +//////////////////////////////////////////////////////////// +- (void)show:(bool)flag; + +//////////////////////////////////////////////////////////// +/// Forward call to en/disable the OpenGL view vertical synchronization +//////////////////////////////////////////////////////////// +- (void)enableVerticalSync:(bool)flag; + +//////////////////////////////////////////////////////////// +/// Forward 'setActive' call the the OpenGL view +//////////////////////////////////////////////////////////// +- (void)setActive:(bool)flag; + +//////////////////////////////////////////////////////////// +/// Forward call to flush the OpenGL view +//////////////////////////////////////////////////////////// +- (void)flushBuffer; + +@end + diff --git a/src/SFML/Window/Cocoa/GLKit.mm b/src/SFML/Window/Cocoa/GLKit.mm new file mode 100644 index 000000000..71d4259a9 --- /dev/null +++ b/src/SFML/Window/Cocoa/GLKit.mm @@ -0,0 +1,1017 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Lucas Soltic (ceylow@gmail.com) and Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#import +#import +#import +#import +#import +#import +#import + + +//////////////////////////////////////////////////////////// +/// Window independant OpenGL context class +//////////////////////////////////////////////////////////// +@implementation GLContext + +static GLContext *sharedCtx = nil; + +//////////////////////////////////////////////////////////// +/// Return the shared OpenGL context instance (making one if needed) +//////////////////////////////////////////////////////////// ++ (id)sharedContext +{ + if (sharedCtx == nil) + { + // Make a new context with the default parameters + sf::WindowSettings params(0, 0, 0); + sharedCtx = [[GLContext alloc] initWithAttributes:params sharedContext:nil]; + } + + return sharedCtx; +} + +- (void)dealloc +{ + [mySharedContext release]; + [super dealloc]; +} + +//////////////////////////////////////////////////////////// +/// Make a new OpenGL context according to the @attribs settings +/// and the shared context @context +//////////////////////////////////////////////////////////// +- (id)initWithAttributes:(sf::WindowSettings&)attribs sharedContext:(GLContext *)context +{ + // Note about antialiasing and other context attributes : + // OpenGL context sharing does not allow the shared contexts to use different attributes. + // The point is that the default shared global OpenGL context uses default parameters. + // That means that all the other context *should* use the same paramaters. + // Fortunately some values parameters for some parameters are compatible, but some are not + // among which : the antialising level. + // + // I've no way to fix this for now. + + NSOpenGLPixelFormat *myPixelFormat = nil; + unsigned idx = 0; + + // Attributes list + NSOpenGLPixelFormatAttribute ctxtAttribs[15] = {(NSOpenGLPixelFormatAttribute) 0}; + + // Accelerated, double buffered + ctxtAttribs[idx++] = NSOpenGLPFAClosestPolicy; + ctxtAttribs[idx++] = NSOpenGLPFADoubleBuffer; + ctxtAttribs[idx++] = NSOpenGLPFAAccelerated; + + // windowed context (even fullscreen mode uses a window) + ctxtAttribs[idx++] = NSOpenGLPFAWindow; + + // Color size ; usually 32 bits per pixel + ctxtAttribs[idx++] = NSOpenGLPFAColorSize; + ctxtAttribs[idx++] = (NSOpenGLPixelFormatAttribute) sf::VideoMode::GetDesktopMode().BitsPerPixel; + + // Z-buffer size + ctxtAttribs[idx++] = NSOpenGLPFADepthSize; + ctxtAttribs[idx++] = (NSOpenGLPixelFormatAttribute) attribs.DepthBits; + + // Stencil bits (I don't really know what's that...) + ctxtAttribs[idx++] = NSOpenGLPFAStencilSize; + ctxtAttribs[idx++] = (NSOpenGLPixelFormatAttribute) attribs.StencilBits; + + myPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:ctxtAttribs]; + + if (myPixelFormat) { + self = [super initWithFormat:myPixelFormat + shareContext:context]; + + mySharedContext = [context retain]; + + // Get the effective properties from our OpenGL context + GLint tmpDepthSize = 0, tmpStencilBits = 0, tmpAntialiasingLevel = 0; + + if (self) { + [myPixelFormat getValues:&tmpDepthSize + forAttribute:NSOpenGLPFADepthSize + forVirtualScreen:[self currentVirtualScreen]]; + + [myPixelFormat getValues:&tmpStencilBits + forAttribute:NSOpenGLPFAStencilSize + forVirtualScreen:[self currentVirtualScreen]]; + + [myPixelFormat getValues:&tmpAntialiasingLevel + forAttribute:NSOpenGLPFASamples + forVirtualScreen:[self currentVirtualScreen]]; + } + + + attribs.DepthBits = (unsigned) tmpDepthSize; + attribs.StencilBits = (unsigned) tmpStencilBits; + attribs.AntialiasingLevel = (unsigned) tmpAntialiasingLevel; + + [myPixelFormat release]; + } + + return self; +} + +@end + + +//////////////////////////////////////////////////////////// +/// Customized Cocoa OpenGL view +//////////////////////////////////////////////////////////// +@implementation GLView + +//////////////////////////////////////////////////////////// +/// 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 +{ + assert(delegate != NULL); + + // make the view + self = [super initWithFrame:frame pixelFormat:nil]; + + if (self) + { + // enabled auto-resizing + [self setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + + // make the OpenGL context + myGLContext = [[GLContext alloc] initWithAttributes:settings sharedContext:sharedCtx]; + + // We need to update the OpenGL view when it's resized + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc addObserver:self + selector:@selector(viewFrameDidChange:) + name:NSViewFrameDidChangeNotification + object:self]; + + // Save the delegate + myDelegate = delegate; + } + + return self; +} + + +//////////////////////////////////////////////////////////// +/// Clean the instance +//////////////////////////////////////////////////////////// +- (void)dealloc +{ + // Remove the observer and release the OpenGL context + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [myGLContext release]; + + [super dealloc]; +} + + +//////////////////////////////////////////////////////////// +/// Finish view setting (after having added it to the window) +//////////////////////////////////////////////////////////// +- (void)finishInitialization +{ + assert([self superview] != nil); + assert(myGLContext != nil); + + // Attach the OpenGL context to our view + [self clearGLContext]; + [self setOpenGLContext:myGLContext]; + [myGLContext setView:self]; + + // Make our view the first responder + [[self window] makeFirstResponder:self]; +} + + +//////////////////////////////////////////////////////////// +/// Forward call to en/disable vertical synchronization +//////////////////////////////////////////////////////////// +- (void)enableVerticalSync:(bool)flag +{ + GLint enable = (flag) ? 1 : 0; + [[self openGLContext] setValues:&enable forParameter:NSOpenGLCPSwapInterval]; +} + + +//////////////////////////////////////////////////////////// +/// Forward call to set the OpenGL context as active according to @flag +//////////////////////////////////////////////////////////// +- (void)setActive:(bool)flag +{ + if (flag) { + if ([NSOpenGLContext currentContext] != [self openGLContext]) + [[self openGLContext] makeCurrentContext]; + } else { + if ([NSOpenGLContext currentContext] == [self openGLContext]) + [NSOpenGLContext clearCurrentContext]; + } +} + + +//////////////////////////////////////////////////////////// +/// Forward call to flush the OpenGL context +//////////////////////////////////////////////////////////// +- (void)flushBuffer +{ + [[self openGLContext] flushBuffer]; +} + + +//////////////////////////////////////////////////////////// +/// Send event to the linked window +//////////////////////////////////////////////////////////// +- (void)pushEvent:(sf::Event)sfEvent +{ + assert(myDelegate != NULL); + myDelegate->HandleNotifiedEvent(sfEvent); +} + + +//////////////////////////////////////////////////////////// +/// Notification method receiver when OpenGL view size changes +//////////////////////////////////////////////////////////// +- (void)viewFrameDidChange:(NSNotification *)notification +{ + [self update]; + + sf::Event ev; + ev.Type = sf::Event::Resized; + ev.Size.Width = (unsigned) [self frame].size.width; + ev.Size.Height = (unsigned) [self frame].size.height; + + [self pushEvent:ev]; +} + + +//////////////////////////////////////////////////////////// +/// Notification method receiver when the window gains focus +//////////////////////////////////////////////////////////// +- (void)windowDidBecomeMain:(NSNotification *)notification +{ + sf::Event ev; + ev.Type = sf::Event::GainedFocus; + + [self pushEvent:ev]; +} + + +//////////////////////////////////////////////////////////// +/// Notification method receiver when the window loses focus +//////////////////////////////////////////////////////////// +- (void)windowDidResignMain:(NSNotification *)notification +{ + sf::Event ev; + ev.Type = sf::Event::LostFocus; + + [self pushEvent:ev]; +} + + +//////////////////////////////////////////////////////////// +/// Notification method receiver when the window closes +//////////////////////////////////////////////////////////// +- (void)windowWillClose:(NSNotification *)notification +{ + sf::Event ev; + ev.Type = sf::Event::Closed; + + [self pushEvent:ev]; +} + +//////////////////////////////////////////////////////////// +/// Notification method receiver when the window finish moving +//////////////////////////////////////////////////////////// +- (void)windowDidMove:(NSNotification *)notification +{ + NSWindow *sender = [notification object]; + + if (!([sender styleMask] & NSTitledWindowMask)) + [sender center]; +} + + +//////////////////////////////////////////////////////////// +/// Receiver method called when a key is pressed +//////////////////////////////////////////////////////////// +- (void)keyDown:(NSEvent *)theEvent +{ + assert(myDelegate != NULL); + myDelegate->HandleKeyDown(theEvent); +} + + +//////////////////////////////////////////////////////////// +/// Receiver method called when a key is released +//////////////////////////////////////////////////////////// +- (void)keyUp:(NSEvent *)theEvent +{ + assert(myDelegate != NULL); + myDelegate->HandleKeyUp(theEvent); +} + + +//////////////////////////////////////////////////////////// +/// Receiver method called when a modifier flag has changed +//////////////////////////////////////////////////////////// +- (void)flagsChanged:(NSEvent *)theEvent +{ + assert(myDelegate != NULL); + myDelegate->HandleModifierKey(theEvent); +} + + +//////////////////////////////////////////////////////////// +/// Receiver method called when the mouse wheel has been used +//////////////////////////////////////////////////////////// +- (void)scrollWheel:(NSEvent *)theEvent +{ + assert(myDelegate != NULL); + myDelegate->HandleMouseWheel(theEvent); +} + + +//////////////////////////////////////////////////////////// +/// Receiver method called when left mouse click is pressed +//////////////////////////////////////////////////////////// +- (void)mouseDown:(NSEvent *)theEvent +{ + assert(myDelegate != NULL); + myDelegate->HandleMouseDown(theEvent); +} + + +//////////////////////////////////////////////////////////// +/// Receiver method called when right mouse click is pressed +//////////////////////////////////////////////////////////// +- (void)rightMouseDown:(NSEvent *)theEvent +{ + assert(myDelegate != NULL); + myDelegate->HandleMouseDown(theEvent); +} + + +//////////////////////////////////////////////////////////// +/// Receiver method called when left mouse click is released +//////////////////////////////////////////////////////////// +- (void)mouseUp:(NSEvent *)theEvent +{ + assert(myDelegate != NULL); + myDelegate->HandleMouseUp(theEvent); +} + + +//////////////////////////////////////////////////////////// +/// Receiver method called when right mouse click is released +//////////////////////////////////////////////////////////// +- (void)rightMouseUp:(NSEvent *)theEvent +{ + assert(myDelegate != NULL); + myDelegate->HandleMouseUp(theEvent); +} + + +//////////////////////////////////////////////////////////// +/// Receiver method called when mouse moves +//////////////////////////////////////////////////////////// +- (void)mouseMoved:(NSEvent *)theEvent +{ + assert(myDelegate != NULL); + myDelegate->HandleMouseMove(theEvent); +} + +//////////////////////////////////////////////////////////// +/// Receiver method called when mouse is pressed (on left button) and moves +//////////////////////////////////////////////////////////// +- (void)mouseDragged:(NSEvent *)theEvent +{ + assert(myDelegate != NULL); + myDelegate->HandleMouseMove(theEvent); +} + +//////////////////////////////////////////////////////////// +/// Receiver method called when mouse is pressed (on right button) and moves +//////////////////////////////////////////////////////////// +- (void)rightMouseDragged:(NSEvent *)theEvent +{ + assert(myDelegate != NULL); + myDelegate->HandleMouseMove(theEvent); +} + + +//////////////////////////////////////////////////////////// +/// Tells that the view can be focused +//////////////////////////////////////////////////////////// +- (BOOL)acceptsFirstResponder +{ + return YES; +} + + +//////////////////////////////////////////////////////////// +/// Tells that the view can become the key responder (ie. can catch key events) +//////////////////////////////////////////////////////////// +- (BOOL)canBecomeKeyView +{ + return YES; +} + +@end + + +//////////////////////////////////////////////////////////// +/// Cocoa window implementation to let fullscreen windows +/// catch key events +//////////////////////////////////////////////////////////// +@implementation GLWindow + +- (BOOL)canBecomeKeyWindow +{ + return YES; +} + +- (BOOL)canBecomeMainWindow +{ + return YES; +} + +@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 +{ + /* + assert(title != nil); + assert(delegate != NULL); + + self = [super init]; + + if (self) + { + NSRect frame = NSMakeRect (0.0f, 0.0f, (float) mode.Width, (float) mode.Height); + unsigned int mask = 0; + + // We grab options from WindowStyle and add them to our window mask + if (style & sf::Style::None || style & sf::Style::Fullscreen) { + mask |= NSBorderlessWindowMask; + + 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(kCGDirectMainDisplay, 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); + + } + } + + } 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 = [[GLWindow alloc] initWithContentRect:frame + styleMask:mask + backing:NSBackingStoreBuffered + defer:NO]; + + if (myWindow) { + // We set title and window position + [myWindow setTitle:title]; + [myWindow center]; + + // 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 + [self setupGLViewAndWindow]; + } 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; + */ + + return [self initWithWindow:nil + settings:params + videoMode:mode + style:style + title:title + delegate: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 +{ + /* + assert(window != NULL); + assert(delegate != NULL); + + self = [super init]; + + if (self) + { + myWindow = (GLWindow *)[window retain]; + + sf::VideoMode mode([[myWindow contentView] frame].size.width, + [[myWindow contentView] frame].size.height); + + // 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 + [self setupGLViewAndWindow]; + } + else + { + std::cerr << "Unable to create the OpenGL view" << std::endl; + [self autorelease]; + return nil; + } + } + + return self; + */ + + sf::VideoMode mode([[myWindow contentView] frame].size.width, [[myWindow contentView] frame].size.height); + return [self initWithWindow:[window autorelease] + 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 (myWindow) { + myWindow = (GLWindow *)[window retain]; + } else { + assert(title != nil); + + NSRect frame = NSMakeRect (0.0f, 0.0f, (float) mode.Width, (float) mode.Height); + unsigned int mask = 0; + + // We grab options from WindowStyle and add them to our window mask + if (style & sf::Style::None || style & sf::Style::Fullscreen) { + mask |= NSBorderlessWindowMask; + + 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(kCGDirectMainDisplay, 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); + + } + } + + } 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 = [[GLWindow 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:myView + selector:@selector(windowDidBecomeMain:) + name:NSWindowDidBecomeMainNotification + object:myWindow]; + + // We want to know when our window lost the focus + [nc addObserver:myView + selector:@selector(windowDidResignMain:) + name:NSWindowDidResignMainNotification + object:myWindow]; + + // We want to know when the user closes the window + [nc addObserver:myView + 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:myView + 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; +} + +//////////////////////////////////////////////////////////// +/// Finish the window setup (without knowing whether it's a imported +/// window) +//////////////////////////////////////////////////////////// +/* - (void)setupGLViewAndWindow +{ + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + + // We want to know when our window got the focus + [nc addObserver:myView + selector:@selector(windowDidBecomeMain:) + name:NSWindowDidBecomeMainNotification + object:myWindow]; + + // We want to know when our window lost the focus + [nc addObserver:myView + selector:@selector(windowDidResignMain:) + name:NSWindowDidResignMainNotification + object:myWindow]; + + // We want to know when the user closes the window + [nc addObserver:myView + 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:myView + 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]; +} */ + + +//////////////////////////////////////////////////////////// +/// Clean the window wrapper +//////////////////////////////////////////////////////////// +- (void)dealloc +{ + // Remove the notification observer + if (myView) + [[NSNotificationCenter defaultCenter] removeObserver:myView]; + + // Close the window + [self show:false]; + + // Release the window and view + [myView release]; + [myWindow release]; + + [super dealloc]; +} + + +//////////////////////////////////////////////////////////// +/// Return a reference to the internal Cocoa window +//////////////////////////////////////////////////////////// +- (NSWindow *)window +{ + return myWindow; +} + + +//////////////////////////////////////////////////////////// +/// Return a reference to the internal Cocoa OpenGL view +//////////////////////////////////////////////////////////// +- (GLView *)glView +{ + return myView; +} + + +//////////////////////////////////////////////////////////// +/// Forward call to set the window position on screen +//////////////////////////////////////////////////////////// +- (void)setPosition:(NSPoint)pos +{ + assert(myWindow != nil); + + if (!myIsFullscreen) { + // Flip Y and set window position + pos.y = [[myWindow screen] frame].size.height - pos.y; + [myWindow setFrameTopLeftPoint:pos]; + } +} + + +//////////////////////////////////////////////////////////// +/// Forward call to set the window size +//////////////////////////////////////////////////////////// +- (void)setSize:(NSSize)size +{ + assert(myWindow != nil); + + if (!myIsFullscreen) { + [myWindow setFrame:NSMakeRect([myWindow frame].origin.x, + [myWindow frame].origin.y, + size.width, size.height) + display:YES]; + } +} + + +//////////////////////////////////////////////////////////// +/// Return the mouse location relative to the internal window +//////////////////////////////////////////////////////////// +- (NSPoint)mouseLocation +{ + assert(myWindow != nil); + + NSPoint relativeLocation = [myWindow convertScreenToBase:[NSEvent mouseLocation]]; + relativeLocation.y = [[self glView] frame].size.height - relativeLocation.y; + return relativeLocation; +} + + +//////////////////////////////////////////////////////////// +/// Return whether the mouse is on our window +//////////////////////////////////////////////////////////// +- (BOOL)mouseInside +{ + assert(myWindow != nil); + assert(myView != nil); + + BOOL flag = NO; + + if ([myWindow isVisible]) { + NSPoint relativeToWindow = [myWindow mouseLocationOutsideOfEventStream]; + NSPoint relativeToView = [myView convertPoint:relativeToWindow fromView:nil]; + + if (NSPointInRect (relativeToView, [myView bounds])) + { + flag = YES; + } + } + + return flag; +} + + +//////////////////////////////////////////////////////////// +/// Close or open the window +//////////////////////////////////////////////////////////// +- (void)show:(bool)flag +{ + assert(myWindow != nil); + + if (flag && ![myWindow isVisible]) { + // Wanna open the closed window + + if (myIsFullscreen) { + [SharedAppController setFullscreenWindow:self mode:&myFullscreenMode]; + } else { + // Show the window + [myWindow makeKeyAndOrderFront:nil]; + } + } else if (!flag && [myWindow isVisible]) { + // Wanna close the opened window + + if (myIsFullscreen) { + [SharedAppController setFullscreenWindow:nil mode:NULL]; + } else { + // Close the window + [myWindow close]; + } + } +} + + +//////////////////////////////////////////////////////////// +/// Forward call to en/disable the OpenGL view vertical synchronization +//////////////////////////////////////////////////////////// +- (void)enableVerticalSync:(bool)flag +{ + assert(myView != nil); + [myView enableVerticalSync:flag]; +} + + +//////////////////////////////////////////////////////////// +/// Forward 'setActive' call the the OpenGL view +//////////////////////////////////////////////////////////// +- (void)setActive:(bool)flag +{ + assert(myView != nil); + [myView setActive:flag]; +} + + +//////////////////////////////////////////////////////////// +/// Forward call to flush the OpenGL view +//////////////////////////////////////////////////////////// +- (void)flushBuffer +{ + assert(myView != nil); + [myView flushBuffer]; +} + +@end + diff --git a/src/SFML/Window/Cocoa/WindowImplCocoa.hpp b/src/SFML/Window/Cocoa/WindowImplCocoa.hpp index 1b2e96b40..bc93d54ce 100644 --- a/src/SFML/Window/Cocoa/WindowImplCocoa.hpp +++ b/src/SFML/Window/Cocoa/WindowImplCocoa.hpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2008 Lucas Soltic (elmerod@gmail.com) and Laurent Gomila (laurent.gom@gmail.com) +// Copyright (C) 2007-2009 Lucas Soltic (ceylow@gmail.com) and Laurent Gomila (laurent.gom@gmail.com) // // This software is provided 'as-is', without any express or implied warranty. // In no event will the authors be held liable for any damages arising from the use of this software. @@ -32,13 +32,16 @@ #include #include +#ifdef __OBJC__ +#import +@class WindowWrapper; +#endif + namespace sf { namespace priv { -typedef struct objc_members objc_members; - //////////////////////////////////////////////////////////// /// WindowImplCocoa is the Cocoa implementation of WindowImpl //////////////////////////////////////////////////////////// @@ -88,25 +91,23 @@ public : //////////////////////////////////////////////////////////// static bool IsContextActive(); - //////////////////////////////////////////////////////////// - /// Handle Cocoa NSEvent - //////////////////////////////////////////////////////////// - void HandleEvent(void *eventRef); - //////////////////////////////////////////////////////////// /// Handle an event sent by the default NSNotificationCenter //////////////////////////////////////////////////////////// void HandleNotifiedEvent(Event& eventRef); //////////////////////////////////////////////////////////// - /// Return a pointer to the NSWindow (objc->windowHandle) object + /// Event handling for every event type. + /// 'eventRef' is a NSEvent. //////////////////////////////////////////////////////////// - void *CocoaWindow(void); + void HandleKeyDown(void *eventRef); + void HandleKeyUp(void *eventRef); + void HandleModifierKey(void *eventRef); + void HandleMouseDown(void *eventRef); + void HandleMouseUp(void *eventRef); + void HandleMouseMove(void *eventRef); + void HandleMouseWheel(void *eventRef); - //////////////////////////////////////////////////////////// - /// Return whether the window is in full screen mode - //////////////////////////////////////////////////////////// - bool IsFullscreen(void); private : //////////////////////////////////////////////////////////// @@ -182,38 +183,19 @@ private : //////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////// - /// Event handling for every event type. - /// 'eventRef' is a NSEvent. - //////////////////////////////////////////////////////////// - int HandleKeyDown(void *eventRef); - int HandleKeyUp(void *eventRef); - int HandleModifierKey(void *eventRef); - int HandleMouseDown(void *eventRef); - int HandleMouseUp(void *eventRef); - int HandleMouseMove(void *eventRef); - int HandleMouseWheel(void *eventRef); - - //////////////////////////////////////////////////////////// - /// Make some allocations and initializations - //////////////////////////////////////////////////////////// - void Initialize(void); - - //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - // An opaque structure that contains all obj-C objects - objc_members *members; +#ifdef __OBJC__ + WindowWrapper *myWrapper; +#else + void *myWrapper; +#endif - bool useKeyRepeat; - bool mouseIn; - float wheelStatus; - - bool fullscreen; - VideoMode fullscreenMode; - VideoMode desktopMode; + bool myUseKeyRepeat; + bool myMouseIn; + float myWheelStatus; }; } // namespace priv diff --git a/src/SFML/Window/Cocoa/WindowImplCocoa.mm b/src/SFML/Window/Cocoa/WindowImplCocoa.mm index 045803523..4d6746c91 100644 --- a/src/SFML/Window/Cocoa/WindowImplCocoa.mm +++ b/src/SFML/Window/Cocoa/WindowImplCocoa.mm @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////// // // SFML - Simple and Fast Multimedia Library -// Copyright (C) 2007-2008 Lucas Soltic (elmerod@gmail.com) and Laurent Gomila (laurent.gom@gmail.com) +// Copyright (C) 2007-2009 Lucas Soltic (ceylow@gmail.com) and Laurent Gomila (laurent.gom@gmail.com) // // This software is provided 'as-is', without any express or implied warranty. // In no event will the authors be held liable for any damages arising from the use of this software. @@ -27,38 +27,16 @@ // Headers //////////////////////////////////////////////////////////// #import -#import #import +#import #import #import #import #import -#import +#import #import -#pragma mark Notes - -// ENABLE_ANTIALIASING macro : -// -// I use this to prevent the use of antialiasing -// as OpenGL context sharing does not allow only one of the -// shared OpenGL context to be shared. That means -// antialiasing could not be used without re-compiling -// the whole sfml-window library. -// -// I've no way to fix this for now. - -// ENABLE_WINDOWIMPORT macro : -// -// I use this to disable the import of Cocoa windows -// as it does not work fine for now and is not -// a high priority. - - - - - namespace sf { namespace priv @@ -72,81 +50,34 @@ make;\ __done = 1;\ } } -// Has the event been used or not ? If not, it must be sent to NSApp -enum { - UsedEvent, - UnusedEvent -}; - - -//////////////////////////////////////////////////////////// -/// Structure containing all the members I can't directly put in the class definition -/// because I would have to hide them in a #ifdef __OBJC__ block and the object -/// allocator would allocate space for it as it would be called from a C++ code -/// that wouldn't see these members -//////////////////////////////////////////////////////////// -struct objc_members { - WindowController *controller; - SFWindow *window; - NSOpenGLContext *context; - NSOpenGLView *view; -}; - -//////////////////////////////////////////////////////////// -/// Pointer to the shared OpenGL context -//////////////////////////////////////////////////////////// -static NSOpenGLContext *sharedContext = nil; - //////////////////////////////////////////////////////////// /// Private function declarations //////////////////////////////////////////////////////////// -static SFWindow * MakeWindow(WindowSettings& params, unsigned long style, VideoMode& mode, NSString *title); -static NSOpenGLContext *MakeOpenGLContext(WindowSettings& params); -static NSOpenGLView * MakeOpenGLView(SFWindow *window, NSOpenGLContext *context, WindowSettings& params); -static void ConfigureWindow(SFWindow *window, NSOpenGLView *view, WindowController *controller); static Key::Code KeyForVirtualCode(unsigned short vCode); static Key::Code KeyForUnicode(unsigned short uniCode); static bool IsTextEvent(NSEvent *event); -static bool MouseInside(SFWindow *window, NSView *view); -static NSPoint MouseLocation(SFWindow *window); //////////////////////////////////////////////////////////// /// Default constructor /// (creates a dummy window to provide a valid OpenGL context) //////////////////////////////////////////////////////////// + static WindowImplCocoa *globalWin = NULL; WindowImplCocoa::WindowImplCocoa() : -members(NULL), -useKeyRepeat(false), -mouseIn(false), -wheelStatus(0.0f), -fullscreen(false), -fullscreenMode(0, 0, 0), -desktopMode(0, 0, 0) +myWrapper(nil), +myUseKeyRepeat(false), +myMouseIn(false), +myWheelStatus(0.0f) { - Initialize(); + [AppController sharedController]; - // We just want to have a valid support for an OpenGL context - - // So we create the OpenGL context - WindowSettings params(0, 0, 0); - members->context = MakeOpenGLContext(params); - - if (members->context != nil) { - // Increase the reference counter for the shared OpenGL context - sharedContext = [members->context retain]; - + // Create the shared OpenGL context + if ([GLContext sharedContext]) { // Then we make it the current active OpenGL context SetActive(); - - // And set the current working directory to - // the Resources folder is it's a bundled app, - // or to the directory containing the executable otherwise - chdir([[[NSBundle mainBundle] resourcePath] UTF8String]); - } else { - std::cerr << "*** SFML: Unable to make the main shared OpenGL context" << std::endl; + std::cerr << "Unable to make the main shared OpenGL context" << std::endl; } } @@ -155,53 +86,30 @@ desktopMode(0, 0, 0) /// Create the window implementation from an existing control //////////////////////////////////////////////////////////// WindowImplCocoa::WindowImplCocoa(WindowHandle Handle, WindowSettings& params) : -members(NULL), -useKeyRepeat(false), -mouseIn(false), -wheelStatus(0.0f), -fullscreen(false), -fullscreenMode(0, 0, 0), -desktopMode(0, 0, 0) +myWrapper(NULL), +myUseKeyRepeat(false), +myMouseIn(false), +myWheelStatus(0.0f) { - Initialize(); - -#if ENABLE_WINDOWIMPORT - // Register ourselves for event handling - [[AppController sharedController] registerWindow:this]; - - // Make a WindowController to handle notifications - members->controller = [[WindowController controllerWithWindow:this] retain]; - - // Use existing window - members->window = [static_cast (Handle) retain]; - - if (members->window != nil) { - // We make the OpenGL context, associate it to the OpenGL view - // and add the view to our window - members->context = MakeOpenGLContext(params); + if (Handle) + { + // We create the window according to the given handle + myWrapper = [[WindowWrapper alloc] initWithWindow:(NSWindow *)Handle + settings:params + delegate:this]; - if (members->context != nil) { - members->view = MakeOpenGLView(members->window, members->context, params); + if (myWrapper) + { + // initial mouse state + myMouseIn = [myWrapper mouseInside]; - if (members->view != nil) { - // initial mouse state - mouseIn = MouseInside(members->window, members->view); - - // Initialize myWidth and myHeight members from base class with the window size - myWidth = (unsigned) [members->window frame].size.width; - myHeight = (unsigned) [members->window frame].size.height; - } else { - //error(__FILE__, __LINE__, "failed to make the OpenGL view for the public window"); - } + // 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 { - //error(__FILE__, __LINE__, "failed to make the OpenGL context for the public window"); + std::cerr << "Failed to make the public window" << std::endl; } - } else { - //error(__FILE__, __LINE__, "invalid imported window"); } -#else - std::cerr << "*** SFML: making a sf::Window from a Cocoa one is not available in this version of the SFML" << std::endl; -#endif } @@ -209,65 +117,32 @@ desktopMode(0, 0, 0) /// Create the window implementation //////////////////////////////////////////////////////////// WindowImplCocoa::WindowImplCocoa(VideoMode Mode, const std::string& Title, unsigned long WindowStyle, WindowSettings& params) : -members(NULL), -useKeyRepeat(false), -mouseIn(false), -wheelStatus(0.0f), -fullscreen(WindowStyle & Style::Fullscreen), -fullscreenMode(0, 0, 0), -desktopMode(0, 0, 0) +myWrapper(NULL), +myUseKeyRepeat(false), +myMouseIn(false), +myWheelStatus(0.0f) { - Initialize(); - - // Make a WindowController to handle notifications - members->controller = [[WindowController controllerWithWindow:this] retain]; - // Create a new window with given size, title and style // First we define some objects used for our window - NSString *title = massert([NSString stringWithUTF8String:Title.c_str()]); + NSString *title = [NSString stringWithUTF8String:(Title.c_str()) ? (Title.c_str()) : ""]; // We create the window - members->window = MakeWindow(params, WindowStyle, Mode, title); + myWrapper = [[WindowWrapper alloc] initWithSettings:params + videoMode:Mode + style:WindowStyle + title:title + delegate:this]; - - if (members->window != nil) { - members->context = MakeOpenGLContext(params); + if (myWrapper) + { + // initial mouse state + myMouseIn = [myWrapper mouseInside]; - if (members->context != nil) { - // We make the OpenGL context, associate it to the OpenGL view - // and add the view to our window - members->view = MakeOpenGLView(members->window, members->context, params); - - if (members->view != nil) { - // Set observers and some window settings - ConfigureWindow(members->window, members->view, members->controller); - - // initial mouse state - mouseIn = MouseInside(members->window, members->view); - - // We set the myWidth and myHeight members to the correct values - myWidth = Mode.Width; - myHeight = Mode.Height; - - if (WindowStyle & Style::Fullscreen) { - fullscreenMode = Mode; - - // Using this because full screen window was not always - // in front of the other application windows when unhiding app - [members->window setLevel:NSFloatingWindowLevel]; - } - } else { - std::cerr << "*** SFML: failed to make the OpenGL view for the public window" << std::endl; - [members->context release], members->context = nil; - [sharedContext release]; - [members->window release], members->window = nil; - } - } else { - std::cerr << "*** SFML: failed to make the OpenGL context for the public window" << std::endl; - [members->window release], members->window = nil; - } + // We set the myWidth and myHeight members to the correct values + myWidth = Mode.Width; + myHeight = Mode.Height; } else { - std::cerr << "*** SFML: failed to make the public window" << std::endl; + std::cerr << "Failed to make the public window" << std::endl; } } @@ -277,28 +152,11 @@ desktopMode(0, 0, 0) //////////////////////////////////////////////////////////// WindowImplCocoa::~WindowImplCocoa() { - - // Release the notification receiver - if (members) { - [[NSNotificationCenter defaultCenter] removeObserver:members->controller]; - [members->controller release]; - } - // Make sure the window is closed Show(false); - // Decrement the shared context counter - [sharedContext release]; - // Release the window objects - if (members) { - [members->context release]; - [members->view release]; - [members->window release]; - } - - // Free the private members struct - delete members; + [myWrapper release]; } @@ -311,63 +169,6 @@ bool WindowImplCocoa::IsContextActive() } -//////////////////////////////////////////////////////////// -/// Handle a Cocoa NSEvent -//////////////////////////////////////////////////////////// -void WindowImplCocoa::HandleEvent(void *eventRef) -{ - if (eventRef == nil) { - std::cerr << "*** SFML: cannot handle a NULL event. Returning." << std::endl; - return; - } - - NSEvent *event = static_cast (eventRef); - int eventStatus = UnusedEvent; - - switch ([event type]) { - case NSKeyDown: - eventStatus = HandleKeyDown(eventRef); - break; - - case NSKeyUp: - eventStatus = HandleKeyUp(eventRef); - break; - - case NSFlagsChanged: - eventStatus = HandleModifierKey(eventRef); - break; - - case NSScrollWheel: - eventStatus = HandleMouseWheel(eventRef); - break; - - case NSLeftMouseDown: - case NSRightMouseDown: - eventStatus = HandleMouseDown(eventRef); - break; - - case NSLeftMouseUp: - case NSRightMouseUp: - eventStatus = HandleMouseUp(eventRef); - break; - - case NSMouseMoved: - case NSLeftMouseDragged: - case NSRightMouseDragged: - case NSOtherMouseDragged: - eventStatus = HandleMouseMove(eventRef); - break; - - default: - break; - } - - if (eventStatus == UnusedEvent) { - [NSApp sendEvent:event]; - } -} - - //////////////////////////////////////////////////////////// /// Handle event sent by the default NSNotificationCenter //////////////////////////////////////////////////////////// @@ -393,7 +194,7 @@ void WindowImplCocoa::HandleNotifiedEvent(Event& event) //////////////////////////////////////////////////////////// /// Handle a key down event (NSEvent) //////////////////////////////////////////////////////////// -int WindowImplCocoa::HandleKeyDown(void *eventRef) +void WindowImplCocoa::HandleKeyDown(void *eventRef) { NSEvent *event = static_cast (eventRef); @@ -409,93 +210,89 @@ int WindowImplCocoa::HandleKeyDown(void *eventRef) if ([[event charactersIgnoringModifiers] length]) rawchr = [[event charactersIgnoringModifiers] characterAtIndex:0]; - } - - if (mods & NSCommandKeyMask) { - // Application commands - [NSApp sendEvent:event]; - } - - // User events - - if (!useKeyRepeat && [event isARepeat]) { - return UsedEvent; - } - + + // Don't handle repeated events if we chose not to send them + if (!myUseKeyRepeat && [event isARepeat]) + return; + #if 1 - // Is it also a text event ? - if (IsTextEvent(event)) { - // buffer for the UTF-8 characters - const char *utf8Characters = [[event characters] UTF8String]; - - // buffer for the UTF-32 characters - Uint32 utf32Characters[2]; - - // convert the characters - const Uint32 *addr = Unicode::UTF8ToUTF32(utf8Characters, - utf8Characters + length, - utf32Characters); - - // si il y a eu des caracteres convertis ? - if (addr > utf32Characters) { - sfEvent.Type = Event::TextEntered; - sfEvent.Text.Unicode = utf32Characters[0]; + // Is it also a text event ? + if (IsTextEvent(event)) { + // buffer for the UTF-32 characters + Uint32 utf32Characters[2] = {0}; - SendEvent(sfEvent); + // convert the characters + if (!CFStringGetCString ((CFStringRef)[event characters], + (char *)utf32Characters, + sizeof(utf32Characters), + kCFStringEncodingUTF32)) + { + const char *utf8Char = NULL; + if ([[event characters] lengthOfBytesUsingEncoding:NSUTF8StringEncoding]) + utf8Char = [[event characters] UTF8String]; + + std::cerr << "Error while converting the character to UTF32 : " + << ((utf8Char) ? utf8Char : "(undefined)") << std::endl; + } + else + { + sfEvent.Type = Event::TextEntered; + sfEvent.Text.Unicode = utf32Characters[0]; + + SendEvent(sfEvent); + } } - } #else - // Is it also a text event ? - if (IsTextEvent(event)) { - static NSMutableArray *arr = [[NSMutableArray alloc] initWithCapacity:1]; - - sfEvent.Type = Event::TextEntered; - sfEvent.Text.Unicode = chr; - - NSText *field = [members->window fieldEditor:YES forObject:nil]; - [arr addObject:event]; - [field interpretKeyEvents:arr]; - - if ([[field string] length]) { - unichar unichr = [[field string] characterAtIndex:0]; - sfEvent.Text.Unicode = unichr; - SendEvent(sfEvent); + // Is it also a text event ? + if (IsTextEvent(event)) { + static NSMutableArray *arr = [[NSMutableArray alloc] initWithCapacity:1]; - unichar str[2] = {unichr, 0}; - NSLog(@"Char::%@", [NSString stringWithCharacters:str length:2]); + sfEvent.Type = Event::TextEntered; + sfEvent.Text.Unicode = chr; - [field setString:@""]; - [arr removeAllObjects]; + NSText *field = [myWindow fieldEditor:YES forObject:nil]; + [arr addObject:event]; + [field interpretKeyEvents:arr]; + + if ([[field string] length]) { + unichar unichr = [[field string] characterAtIndex:0]; + sfEvent.Text.Unicode = unichr; + SendEvent(sfEvent); + + unichar str[2] = {unichr, 0}; + NSLog(@"Char::%@", [NSString stringWithCharacters:str length:2]); + + [field setString:@""]; + [arr removeAllObjects]; + } + + + } +#endif + + // Anyway it's also a KeyPressed event + sfEvent.Type = Event::KeyPressed; + + // Get the keys + if (Key::Code(0) == (sfEvent.Key.Code = KeyForUnicode(rawchr))) { + sfEvent.Key.Code = KeyForVirtualCode([event keyCode]); } + // Get the modifiers + sfEvent.Key.Alt = mods & NSAlternateKeyMask; + sfEvent.Key.Control = mods & NSControlKeyMask; + sfEvent.Key.Shift = mods & NSShiftKeyMask; + // Send the event + SendEvent(sfEvent); } -#endif - - // Anyway it's also a KeyPressed event - sfEvent.Type = Event::KeyPressed; - - // Get the keys - if (Key::Code(0) == (sfEvent.Key.Code = KeyForUnicode(rawchr))) { - sfEvent.Key.Code = KeyForVirtualCode([event keyCode]); - } - - // Get the modifiers - sfEvent.Key.Alt = mods & NSAlternateKeyMask; - sfEvent.Key.Control = mods & NSControlKeyMask; - sfEvent.Key.Shift = mods & NSShiftKeyMask; - - // Send the event - SendEvent(sfEvent); - - return UsedEvent; } //////////////////////////////////////////////////////////// /// Handle a key up event (NSEvent) //////////////////////////////////////////////////////////// -int WindowImplCocoa::HandleKeyUp(void *eventRef) +void WindowImplCocoa::HandleKeyUp(void *eventRef) { NSEvent *event = static_cast (eventRef); @@ -509,46 +306,47 @@ int WindowImplCocoa::HandleKeyUp(void *eventRef) if ([[event charactersIgnoringModifiers] length]) rawchr = [[event charactersIgnoringModifiers] characterAtIndex:0]; + sfEvent.Type = Event::KeyReleased; + + // Get the code + if (Key::Code(0) == (sfEvent.Key.Code = KeyForUnicode(rawchr))) { + sfEvent.Key.Code = KeyForVirtualCode([event keyCode]); + } + + // Get the modifiers + sfEvent.Key.Alt = mods & NSAlternateKeyMask; + sfEvent.Key.Control = mods & NSControlKeyMask; + sfEvent.Key.Shift = mods & NSShiftKeyMask; + + // Send the event + SendEvent(sfEvent); } - - if (mods & NSCommandKeyMask) { - [NSApp sendEvent:event]; - } - - sfEvent.Type = Event::KeyReleased; - - // Get the code - if (Key::Code(0) == (sfEvent.Key.Code = KeyForUnicode(rawchr))) { - sfEvent.Key.Code = KeyForVirtualCode([event keyCode]); - } - - // Get the modifiers - sfEvent.Key.Alt = mods & NSAlternateKeyMask; - sfEvent.Key.Control = mods & NSControlKeyMask; - sfEvent.Key.Shift = mods & NSShiftKeyMask; - - SendEvent(sfEvent); - - return UsedEvent; } //////////////////////////////////////////////////////////// /// Handle a key modifier event [Command, Option, Control, Shift] //////////////////////////////////////////////////////////// -int WindowImplCocoa::HandleModifierKey(void *eventRef) +void WindowImplCocoa::HandleModifierKey(void *eventRef) { NSEvent *event = static_cast (eventRef); Event sfEvent; unsigned mods = [event modifierFlags]; sfEvent.Type = Event::KeyPressed; + + // Get the code sfEvent.Key.Code = KeyForVirtualCode([event keyCode]); + // Get the modifiers sfEvent.Key.Alt = mods & NSAlternateKeyMask; sfEvent.Key.Control = mods & NSControlKeyMask; sfEvent.Key.Shift = mods & NSShiftKeyMask; + // Guess whether it's a pressed or released event + // Note: this does not work fine is both left and right modifiers are pressed + // I did not find any way to fix this. + // TODO: fix handling of modifier flags for use of left and right key at the same time if (!(mods & NSAlternateKeyMask) && (sfEvent.Key.Code == Key::LAlt || sfEvent.Key.Code == Key::RAlt)) { sfEvent.Type = Event::KeyReleased; @@ -569,16 +367,15 @@ int WindowImplCocoa::HandleModifierKey(void *eventRef) sfEvent.Type = Event::KeyReleased; } + // Send the event SendEvent(sfEvent); - - return UnusedEvent; } //////////////////////////////////////////////////////////// /// Handle a mouse down event (NSEvent) //////////////////////////////////////////////////////////// -int WindowImplCocoa::HandleMouseDown(void *eventRef) +void WindowImplCocoa::HandleMouseDown(void *eventRef) { NSEvent *event = static_cast (eventRef); Event sfEvent; @@ -589,18 +386,20 @@ int WindowImplCocoa::HandleMouseDown(void *eventRef) case NSLeftMouseDown: sfEvent.Type = Event::MouseButtonPressed; + // Guess whether it's a mouse left or mouse right event if (mods & NSControlKeyMask) { sfEvent.MouseButton.Button = Mouse::Right; } else { sfEvent.MouseButton.Button = Mouse::Left; } - // Get mouse position - loc = MouseLocation(members->window); + // Get mouse position relative to the window + loc = [myWrapper mouseLocation]; sfEvent.MouseButton.X = (int) loc.x; sfEvent.MouseButton.Y = (int) loc.y; + // Send the event SendEvent(sfEvent); break; @@ -608,28 +407,26 @@ int WindowImplCocoa::HandleMouseDown(void *eventRef) sfEvent.Type = Event::MouseButtonPressed; sfEvent.MouseButton.Button = Mouse::Right; - // Get mouse position - loc = MouseLocation(members->window); + // Get mouse position relative to the window + loc = [myWrapper mouseLocation]; sfEvent.MouseButton.X = (int) loc.x; sfEvent.MouseButton.Y = (int) loc.y; + // Send the event SendEvent(sfEvent); break; default: break; } - - return UnusedEvent; - } //////////////////////////////////////////////////////////// /// Handle a mouse up event (NSEvent) //////////////////////////////////////////////////////////// -int WindowImplCocoa::HandleMouseUp(void *eventRef) +void WindowImplCocoa::HandleMouseUp(void *eventRef) { NSEvent *event = static_cast (eventRef); Event sfEvent; @@ -640,18 +437,20 @@ int WindowImplCocoa::HandleMouseUp(void *eventRef) case NSLeftMouseUp: sfEvent.Type = Event::MouseButtonReleased; + // Guess whether it's a mouse left or mouse right event if (mods & NSControlKeyMask) { sfEvent.MouseButton.Button = Mouse::Right; } else { sfEvent.MouseButton.Button = Mouse::Left; } - // Get mouse position - loc = MouseLocation(members->window); + // Get mouse position relative to the window + loc = [myWrapper mouseLocation]; sfEvent.MouseButton.X = (int) loc.x; sfEvent.MouseButton.Y = (int) loc.y; + // Send the event SendEvent(sfEvent); break; @@ -659,32 +458,31 @@ int WindowImplCocoa::HandleMouseUp(void *eventRef) sfEvent.Type = Event::MouseButtonReleased; sfEvent.MouseButton.Button = Mouse::Right; - // Get mouse position - loc = MouseLocation(members->window); + // Get mouse position relative to the window + loc = [myWrapper mouseLocation]; sfEvent.MouseButton.X = (int) loc.x; sfEvent.MouseButton.Y = (int) loc.y; + // Send the event SendEvent(sfEvent); break; default: break; } - - return UnusedEvent; } //////////////////////////////////////////////////////////// /// Handle a mouse move event (NSEvent) //////////////////////////////////////////////////////////// -int WindowImplCocoa::HandleMouseMove(void *eventRef) +void WindowImplCocoa::HandleMouseMove(void *eventRef) { Event sfEvent; NSPoint loc = {0, 0}; - loc = MouseLocation(members->window); + loc = [myWrapper mouseLocation]; sfEvent.Type = Event::MouseMoved; sfEvent.MouseMove.X = (int) loc.x; @@ -692,65 +490,55 @@ int WindowImplCocoa::HandleMouseMove(void *eventRef) SendEvent(sfEvent); - // MouseEntered and MouseLeft events - if (MouseInside(members->window, members->view) && !mouseIn) { + if ([myWrapper mouseInside] && !myMouseIn) { + // If mouse IS inside but WAS not inside last time sfEvent.Type = Event::MouseEntered; - mouseIn = true; + myMouseIn = true; + SendEvent(sfEvent); - } else if (!MouseInside(members->window, members->view) && mouseIn) { + } else if (![myWrapper mouseInside] && myMouseIn) { + // Is mouse WAS not inside but IS now inside sfEvent.Type = Event::MouseLeft; - mouseIn = false; + myMouseIn = false; + SendEvent(sfEvent); } - - return UnusedEvent; } //////////////////////////////////////////////////////////// /// Handle a mouse wheel event (NSEvent) //////////////////////////////////////////////////////////// -int WindowImplCocoa::HandleMouseWheel(void *eventRef) +void WindowImplCocoa::HandleMouseWheel(void *eventRef) { NSEvent *event = static_cast (eventRef); - wheelStatus += [event deltaY]; + // SFML uses integer values for delta but Cocoa uses float and it is mostly fewer than 1.0 + // Therefore I chose to add the float value to a 'wheel status' and + // send a sf event only when it's greater than 1.0 + myWheelStatus += [event deltaY]; - if (fabs(wheelStatus) > 1.0f) { + if (fabs(myWheelStatus) > 1.0f) { + // Make the event and send it Event sfEvent; sfEvent.Type = Event::MouseWheelMoved; - sfEvent.MouseWheel.Delta = (int) wheelStatus; + sfEvent.MouseWheel.Delta = (int) myWheelStatus; SendEvent(sfEvent); - wheelStatus -= (int) wheelStatus; + // Remove as much integer units as the one that have been put in the event + // (was a mistake to set this to 0) + myWheelStatus -= (int) myWheelStatus; } +} + - return UnusedEvent; -} - - -//////////////////////////////////////////////////////////// -/// Return a pointer to the SFWindow object -//////////////////////////////////////////////////////////// -void *WindowImplCocoa::CocoaWindow(void) -{ - return static_cast (members->window); -} - -//////////////////////////////////////////////////////////// -/// Return whether the window is in full screen mode -//////////////////////////////////////////////////////////// -bool WindowImplCocoa::IsFullscreen(void) -{ - return fullscreen; -} - //////////////////////////////////////////////////////////// /// /see sfWindowImpl::Display //////////////////////////////////////////////////////////// void WindowImplCocoa::Display() { - [members->context flushBuffer]; + // Forward flush call to the window + [myWrapper flushBuffer]; } @@ -759,10 +547,8 @@ void WindowImplCocoa::Display() //////////////////////////////////////////////////////////// void WindowImplCocoa::ProcessEvents() { - if (![NSApp isRunning]) - return; - - [[AppController sharedController] processEvents]; + // Forward event handling call to the application controller + [SharedAppController processEvents]; } @@ -771,13 +557,8 @@ void WindowImplCocoa::ProcessEvents() //////////////////////////////////////////////////////////// void WindowImplCocoa::SetActive(bool Active) const { - if (Active) { - if ([NSOpenGLContext currentContext] != members->context) - [members->context makeCurrentContext]; - } else { - if ([NSOpenGLContext currentContext] == members->context) - [NSOpenGLContext clearCurrentContext]; - } + // Forward the call to the window + [myWrapper setActive:Active]; } @@ -786,8 +567,8 @@ void WindowImplCocoa::SetActive(bool Active) const //////////////////////////////////////////////////////////// void WindowImplCocoa::UseVerticalSync(bool Enabled) { - GLint enable = (Enabled) ? 1 : 0; - [members->context setValues:&enable forParameter:NSOpenGLCPSwapInterval]; + // Forward the call to the window + [myWrapper enableVerticalSync:Enabled]; } @@ -811,24 +592,21 @@ void WindowImplCocoa::SetCursorPosition(unsigned int Left, unsigned int Top) { NSPoint pos = NSMakePoint ((float) Left, (float) Top); - if (members->window) { + if (myWrapper) { // Flip for SFML window coordinate system - pos.y = [members->window frame].size.height - pos.y; + pos.y = [[myWrapper window] frame].size.height - pos.y; // Adjust for view reference instead of window - pos.y -= [members->window frame].size.height - [members->view frame].size.height; + pos.y -= [[myWrapper window] frame].size.height - [[myWrapper glView] frame].size.height; // Convert to screen coordinates - NSPoint absolute = [members->window convertBaseToScreen:pos]; + NSPoint absolute = [[myWrapper window] convertBaseToScreen:pos]; // Flip screen coodinates absolute.y = [[NSScreen mainScreen] frame].size.height - absolute.y; // Move cursor CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, CGPointMake(absolute.x, absolute.y)); - } else { - std::cerr << "*** SFML: uninitialized 'members->window' member (objc_members) in " - << this << " (sf::priv::WindowImplCocoa)" << std::endl; } } @@ -838,16 +616,7 @@ void WindowImplCocoa::SetCursorPosition(unsigned int Left, unsigned int Top) //////////////////////////////////////////////////////////// void WindowImplCocoa::SetPosition(int Left, int Top) { - if (members->window) { - if (!fullscreen) { - // Change the window position - Top = (int) [[members->window screen] frame].size.height - Top; - [members->window setFrameTopLeftPoint:NSMakePoint(Left, Top)]; - } - } else { - std::cerr << "*** SFML: uninitialized 'members->window' member (objc_members) in " - << this << " (sf::priv::WindowImplCocoa)"; - } + [myWrapper setPosition:NSMakePoint(Left, Top)]; } @@ -857,17 +626,7 @@ void WindowImplCocoa::SetPosition(int Left, int Top) //////////////////////////////////////////////////////////// void WindowImplCocoa::SetSize(unsigned int Width, unsigned int Height) { - if (members->window) { - if (!fullscreen) { - [members->window setFrame:NSMakeRect([members->window frame].origin.x, - [members->window frame].origin.y, - (float) Width, (float) Height) - display:YES]; - } - } else { - std::cerr << "*** SFML: uninitialized 'members->window' member (objc_members) in " - << this << " (sf::priv::WindowImplCocoa)" << std::endl; - } + [myWrapper setSize:NSMakeSize(Width, Height)]; } @@ -876,83 +635,7 @@ void WindowImplCocoa::SetSize(unsigned int Width, unsigned int Height) //////////////////////////////////////////////////////////// void WindowImplCocoa::Show(bool State) { - if (State && ![members->window isVisible]) { - // Wanna open the closed window - - // Register ourselves for event handling - [[AppController sharedController] registerWindow:this]; - - if (fullscreen) { - desktopMode = VideoMode::GetDesktopMode(); - - CFDictionaryRef displayMode = CGDisplayBestModeForParameters (kCGDirectMainDisplay, - fullscreenMode.BitsPerPixel, - fullscreenMode.Width, - fullscreenMode.Height, - NULL); - - CGDisplayFadeReservationToken token = kCGDisplayFadeReservationInvalidToken; - - // Fade to a black screen - [SharedAppController doFadeOperation:FillScreen time:0.5f sync:true token:&token]; - [NSMenu setMenuBarVisible:NO]; - - // Switch to the wished display mode - CGDisplaySwitchToMode(kCGDirectMainDisplay, displayMode); - - // Open the window - [members->window makeKeyAndOrderFront:nil]; - [members->window center]; - - // Fade to normal screen - [SharedAppController doFadeOperation:CleanScreen time:0.2f sync:false token:&token]; - - } else { - // Show the window - // Note: using these two lines instead of -[NSWindow makeKeyAndOrderFront:] - // in order to prevent the standard window buttons from not displaying - // the "mouse over" icons - [members->window orderFront:nil]; - [members->window makeKeyWindow]; - - } - } else if (!State && [members->window isVisible]) { - // Wanna close the opened window - - if (fullscreen) { - CFDictionaryRef displayMode = CGDisplayBestModeForParameters (kCGDirectMainDisplay, - desktopMode.BitsPerPixel, - desktopMode.Width, - desktopMode.Height, - NULL); - - CGDisplayFadeReservationToken token = kCGDisplayFadeReservationInvalidToken; - - // Fade to black screen - [SharedAppController doFadeOperation:FillScreen time:0.2f sync:true token:&token]; - - // Switch to the wished display mode - CGDisplaySwitchToMode(kCGDirectMainDisplay, displayMode); - - // Close the window - [members->window close]; - [NSMenu setMenuBarVisible:YES]; - - // Fade to normal screen - [SharedAppController doFadeOperation:CleanScreen time:0.5f sync:false token:&token]; - - // Do not sync but sleep so that the Dock and the Finder desktop go back to normal - // state before the end of the fade operation - sf::Sleep(0.5f); - } else { - // Close the window - [members->window close]; - - } - - // Unregister ourselves from the event handler - [[AppController sharedController] unregisterWindow:this]; - } + [myWrapper show:State]; } @@ -961,7 +644,7 @@ void WindowImplCocoa::Show(bool State) //////////////////////////////////////////////////////////// void WindowImplCocoa::EnableKeyRepeat(bool Enabled) { - useKeyRepeat = Enabled; + myUseKeyRepeat = Enabled; } @@ -974,270 +657,6 @@ void WindowImplCocoa::SetIcon(unsigned int Width, unsigned int Height, const Uin } -//////////////////////////////////////////////////////////// -/// Make some allocations and initializations -//////////////////////////////////////////////////////////// -void WindowImplCocoa::Initialize(void) -{ - // Allocate mem for the private objc members - members = new objc_members; - bzero(members, sizeof(*members)); - - // Needed to always have an autorelease pool as soon as application is launched - ONCE([SharedAppController resetPool]); - - // Register application if needed and launch it - ONCE([SharedAppController runApplication]); -} - - -//////////////////////////////////////////////////////////// -/// Make the window -//////////////////////////////////////////////////////////// -static SFWindow *MakeWindow(WindowSettings& params, unsigned long style, VideoMode& mode, NSString *title) -{ - SFWindow *window = nil; - - NSRect frame = NSMakeRect (0.0f, 0.0f, (float) mode.Width, (float) mode.Height); - unsigned int mask = 0; - - // We grab options from WindowStyle and add them to our window mask - if (style & Style::None || style & Style::Fullscreen) { - mask |= NSBorderlessWindowMask; - - if (style & Style::Fullscreen) { - // Check display mode and put new values in 'mode' if needed - boolean_t exact = true; - CFDictionaryRef properties = CGDisplayBestModeForParameters(kCGDirectMainDisplay, mode.BitsPerPixel, - mode.Width, mode.Height, &exact); - - if (!properties) { - std::cerr << "*** SFML: unable to get a display mode with the given parameters" << std::endl; - 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); - } - } - - } else { - if (style & Style::Titlebar) { - mask |= NSTitledWindowMask; - mask |= NSMiniaturizableWindowMask; - } - - if (style & Style::Resize) { - mask |= NSTitledWindowMask; - mask |= NSMiniaturizableWindowMask; - mask |= NSResizableWindowMask; - } - - if (style & 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 - window =[massert([SFWindow alloc]) initWithContentRect:frame - styleMask:mask - backing:NSBackingStoreBuffered - defer:NO]; - - if (window != nil) { - // We set title and window position - [window setTitle:title]; - [window center]; - } - - return window; -} - - -//////////////////////////////////////////////////////////// -/// Make the OpenGL pixel format from the given attributes -//////////////////////////////////////////////////////////// -static NSOpenGLContext *MakeOpenGLContext(WindowSettings& params) -{ - NSOpenGLPixelFormat *pixFormat = nil; - NSOpenGLContext *context = nil; - unsigned idx = 0; -#if ENABLE_ANTIALIASING - unsigned samplesIdx = 0; -#endif - - // Attributes list - NSOpenGLPixelFormatAttribute attribs[15] = {(NSOpenGLPixelFormatAttribute) 0}; - - // Accelerated, double buffered - attribs[idx++] = NSOpenGLPFAClosestPolicy; - attribs[idx++] = NSOpenGLPFADoubleBuffer; - attribs[idx++] = NSOpenGLPFAAccelerated; - - // windowed context - attribs[idx++] = NSOpenGLPFAWindow; - - // Color size ; usually 32 bits per pixel - attribs[idx++] = NSOpenGLPFAColorSize; - attribs[idx++] = (NSOpenGLPixelFormatAttribute) VideoMode::GetDesktopMode().BitsPerPixel; - - // Z-buffer size - attribs[idx++] = NSOpenGLPFADepthSize; - attribs[idx++] = (NSOpenGLPixelFormatAttribute) params.DepthBits; - - // Stencil bits (I don't really know what's that...) - attribs[idx++] = NSOpenGLPFAStencilSize; - attribs[idx++] = (NSOpenGLPixelFormatAttribute) params.StencilBits; - -#if ENABLE_ANTIALIASING - // Antialiasing settings - if (params.AntialiasingLevel) { - samplesIdx = idx; - - attribs[idx++] = NSOpenGLPFASamples; - attribs[idx++] = (NSOpenGLPixelFormatAttribute) params.AntialiasingLevel; - - attribs[idx++] = NSOpenGLPFASampleBuffers; - attribs[idx++] = (NSOpenGLPixelFormatAttribute) GL_TRUE; - } -#endif - - pixFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; - -#if ENABLE_ANTIALIASING - // If pixel format creation fails and antialiasing level is - // greater than 2, we set it to 2. - if (pixFormat == nil && params.AntialiasingLevel > 2) { - std::cerr << "Failed to find a pixel format supporting " << params.AntialiasingLevel << " antialiasing levels ; trying with 2 levels" << std::endl; - params.AntialiasingLevel = attribs[samplesIdx + 1] = (NSOpenGLPixelFormatAttribute) 2; - - pixFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; - } - - // If pixel format creation fails and antialiasing is enabled, - // we disable it. - if (pixFormat == nil && params.AntialiasingLevel > 0) { - std::cerr << "Failed to find a pixel format supporting antialiasing ; antialiasing will be disabled" << std::endl; - attribs[samplesIdx] = (NSOpenGLPixelFormatAttribute) nil; - - pixFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; - } -#endif - - if (pixFormat) { - context = [[NSOpenGLContext alloc] initWithFormat:pixFormat - shareContext:[sharedContext retain]]; - - // Get the effective properties from our OpenGL context - GLint tmpDepthSize = 0, tmpStencilBits = 0, tmpAntialiasingLevel = 0; - - if (context) { - [pixFormat getValues:&tmpDepthSize - forAttribute:NSOpenGLPFADepthSize - forVirtualScreen:[context currentVirtualScreen]]; - - [pixFormat getValues:&tmpStencilBits - forAttribute:NSOpenGLPFAStencilSize - forVirtualScreen:[context currentVirtualScreen]]; - - [pixFormat getValues:&tmpAntialiasingLevel - forAttribute:NSOpenGLPFASamples - forVirtualScreen:[context currentVirtualScreen]]; - } - - - params.DepthBits = (unsigned) tmpDepthSize; - params.StencilBits = (unsigned) tmpStencilBits; - params.AntialiasingLevel = (unsigned) tmpAntialiasingLevel; - - [pixFormat release]; - } - - return context; -} - - -static NSOpenGLView * MakeOpenGLView(SFWindow *window, NSOpenGLContext *context, WindowSettings& params) -{ - assert(window != nil); - assert(context != nil); - - NSOpenGLView *view = nil; - - - // We make the NSOpenGLView - view = [[NSOpenGLView alloc] initWithFrame:[[window contentView] bounds] - pixelFormat:nil]; - - if (view) { - // We add the NSOpenGLView to the window - [[window contentView] addSubview:view]; - - [view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - [view clearGLContext]; - [view setOpenGLContext:context]; - [context setView:view]; - } - - return view; -} - - -static void ConfigureWindow(SFWindow *window, NSOpenGLView *view, WindowController *controller) -{ - assert(window != nil); - assert(view != nil); - assert(controller != nil); - - // We need to update the OpenGL view when it changes - NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; - [nc addObserver:controller - selector:@selector(viewFrameDidChange:) - name:NSViewFrameDidChangeNotification - object:view]; - - // We want to know when our window got the focus - [nc addObserver:controller - selector:@selector(windowDidBecomeMain:) - name:NSWindowDidBecomeMainNotification - object:window]; - - // We want to know when our window lost the focus - [nc addObserver:controller - selector:@selector(windowDidResignMain:) - name:NSWindowDidResignMainNotification - object:window]; - - // We want to know when the user closes the window - [nc addObserver:controller - selector:@selector(windowWillClose:) - name:NSWindowWillCloseNotification - object:window]; - - // I want to re-center the window if it's a full screen one and moved by Spaces - [nc addObserver:controller - selector:@selector(windowDidMove:) - name:NSWindowDidMoveNotification - object:window]; - - - // Needed not to make application crash when releasing the window in our destructor - // (I prefer to take control of everything :P) - [window setReleasedWhenClosed:NO]; - [window setAcceptsMouseMovedEvents:YES]; -} - - //////////////////////////////////////////////////////////// /// Return the SFML key corresponding to a key code //////////////////////////////////////////////////////////// @@ -1295,7 +714,7 @@ static Key::Code KeyForVirtualCode(unsigned short vCode) {0x36, Key::RSystem}, //< Right Command {0x3C, Key::RShift}, //< Right Shift - {0x39, Key::Code(0)} //< Caps Lock + {0x39, Key::Code(0)} //< Caps Lock (not handled by SFML for now) }; Key::Code result = Key::Code(0); @@ -1316,6 +735,7 @@ static Key::Code KeyForVirtualCode(unsigned short vCode) //////////////////////////////////////////////////////////// static Key::Code KeyForUnicode(unsigned short uniCode) { + // TODO: find a better way to get the language independant key static struct { unsigned short character; Key::Code sfKey; @@ -1415,43 +835,6 @@ static bool IsTextEvent(NSEvent *event) return res; } - -//////////////////////////////////////////////////////////// -/// Return whether the mouse is on our OpenGL view -//////////////////////////////////////////////////////////// -static bool MouseInside(SFWindow *window, NSView *view) -{ - bool res = false; - - if (window && view && [window isVisible]) { - NSPoint relativeToWindow = [window mouseLocationOutsideOfEventStream]; - NSPoint relativeToView = [view convertPoint:relativeToWindow fromView:nil]; - - if (NSPointInRect (relativeToView, [view bounds])) - res = true; - } - - return res; -} - - -//////////////////////////////////////////////////////////// -/// Return the mouse location in the SFML coordinates according to 'window' -//////////////////////////////////////////////////////////// -static NSPoint MouseLocation(SFWindow *window) -{ - NSPoint location = [NSEvent mouseLocation]; - NSPoint relativeLocation = {0, 0}; - - if (window) { - relativeLocation = [window convertScreenToBase:location]; - relativeLocation.y = [[window contentView] frame].size.height - relativeLocation.y; - } else { - std::cerr << "*** SFML: tried to get mouse location from no window" << std::endl; - } - - return relativeLocation; -} } // namespace priv