diff --git a/CMakeLists.txt b/CMakeLists.txt index 5eefa5d61..75b4f3d62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,9 +53,6 @@ sfml_set_option(SFML_OPENGL_ES ${OPENGL_ES} BOOL "TRUE to use an OpenGL ES imple # Mac OS X specific options if(SFML_OS_MACOSX) - # set default CMAKE_OSX_ARCHITECTURES value to x86_64 - sfml_set_option(CMAKE_OSX_ARCHITECTURES "x86_64" STRING "Build architectures for OS X") - # set default CMAKE_OSX_DEPLOYMENT_TARGET value to 10.7 sfml_set_option(CMAKE_OSX_DEPLOYMENT_TARGET "10.7" STRING "Minimum OS version to target for deployment (at runtime)") @@ -151,12 +148,6 @@ if(SFML_OS_MACOSX) endif() endif() - # Objective-C ARC requires a 64 bit runtime. - if(NOT CMAKE_OSX_ARCHITECTURES STREQUAL "x86_64") - message(FATAL_ERROR "CMAKE_OSX_ARCHITECTURES should be 'x86_64'; SFML doesn't support 32 bit on Mac OS X.") - return() - endif() - # make sure CMAKE_OSX_DEPLOYMENT_TARGET is >= 10.7 if (CMAKE_OSX_DEPLOYMENT_TARGET VERSION_LESS "10.7") message(FATAL_ERROR "CMAKE_OSX_DEPLOYMENT_TARGET (${CMAKE_OSX_DEPLOYMENT_TARGET}) should be 10.7 or better") diff --git a/cmake/Macros.cmake b/cmake/Macros.cmake index ed30ad1db..b969930f9 100644 --- a/cmake/Macros.cmake +++ b/cmake/Macros.cmake @@ -64,11 +64,6 @@ macro(sfml_add_library target) set_target_properties(${target} PROPERTIES COMPILE_FLAGS -fvisibility=hidden) endif() - # On OS X, use Objective-C ARC - if(SFML_OS_MACOSX) - set_target_properties(${target} PROPERTIES COMPILE_FLAGS -fobjc-arc) - endif() - # link the target to its SFML dependencies if(THIS_DEPENDS) target_link_libraries(${target} ${THIS_DEPENDS}) diff --git a/src/SFML/Window/CMakeLists.txt b/src/SFML/Window/CMakeLists.txt index c90639a79..b066545de 100644 --- a/src/SFML/Window/CMakeLists.txt +++ b/src/SFML/Window/CMakeLists.txt @@ -138,6 +138,8 @@ elseif(SFML_OS_MACOSX) ${SRCROOT}/OSX/WindowImplCocoa.hpp ${SRCROOT}/OSX/WindowImplCocoa.mm ${SRCROOT}/OSX/WindowImplDelegateProtocol.h + ${SRCROOT}/OSX/AutoreleasePoolWrapper.h + ${SRCROOT}/OSX/AutoreleasePoolWrapper.mm ) source_group("mac" FILES ${PLATFORM_SRC}) elseif(SFML_OS_IOS) diff --git a/src/SFML/Window/OSX/AutoreleasePoolWrapper.h b/src/SFML/Window/OSX/AutoreleasePoolWrapper.h new file mode 100644 index 000000000..8efa8b061 --- /dev/null +++ b/src/SFML/Window/OSX/AutoreleasePoolWrapper.h @@ -0,0 +1,51 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2014 Marco Antognini (antognini.marco@gmail.com), +// 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. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +/// \brief Ensure at least one autorelease pool is available on this thread +/// +/// Increment a retain count. +/// See SPECIAL CONSIDERATION in implementation file. +/// +//////////////////////////////////////////////////////////// +void retainPool(void); + +//////////////////////////////////////////////////////////// +/// \brief Release the pool. +/// +/// Drain the pool if it is no more needed (retain count is zero) +/// See SPECIAL CONSIDERATION in implementation file. +/// +//////////////////////////////////////////////////////////// +void releasePool(void); + +//////////////////////////////////////////////////////////// +/// \brief Drain the pool +/// +/// releasePool must be called at least once before drainPool. +/// +//////////////////////////////////////////////////////////// +void drainPool(); + diff --git a/src/SFML/Window/OSX/AutoreleasePoolWrapper.mm b/src/SFML/Window/OSX/AutoreleasePoolWrapper.mm new file mode 100644 index 000000000..1e7d38363 --- /dev/null +++ b/src/SFML/Window/OSX/AutoreleasePoolWrapper.mm @@ -0,0 +1,225 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2014 Marco Antognini (antognini.marco@gmail.com), +// 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 +//////////////////////////////////////////////////////////// +#include +#include +#include + +#import +#import + + +//////////////////////////////////////////////////////////// +/// Here we manage one and only one pool by thread. This prevents draining one +/// pool and making other pools invalid which can lead to a crash on 10.5 and an +/// annoying message on 10.6 (*** attempt to pop an unknown autorelease pool). +/// +/// Because NSAutoreleasePool cannot be retain we have to do it ourself. +/// We use an sf::ThreadLocalPtr to have one PoolWrapper in each thread. +/// +/// SPECIAL CONSIDERATION: +/// ====================== +/// This implies that if retainPool is called X times in a thread Y then +/// releasePool must be called X times too in the same thread Y. +/// +//////////////////////////////////////////////////////////// + +namespace sf +{ +namespace priv +{ +//////////////////////////////////////////////////////////// +/// \brief C++ Wrapper of Obj-C Autorelease Pool +/// +//////////////////////////////////////////////////////////// +class PoolWrapper : NonCopyable +{ +public : + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + PoolWrapper(); + + //////////////////////////////////////////////////////////// + /// \brief Default destructor + /// + //////////////////////////////////////////////////////////// + ~PoolWrapper(); + + //////////////////////////////////////////////////////////// + /// \brief Increment retain count and allocate memory if needed + /// + //////////////////////////////////////////////////////////// + void retain(); + + //////////////////////////////////////////////////////////// + /// \brief Decrement retain count and releasing memory if needed + /// + //////////////////////////////////////////////////////////// + void release(); + + //////////////////////////////////////////////////////////// + /// \brief Drain the pool + /// + //////////////////////////////////////////////////////////// + void drain(); + +private: + + //////////////////////////////////////////////////////////// + // Member data + //////////////////////////////////////////////////////////// + int m_count; ///< How many times was the pool retained? + NSAutoreleasePool* m_pool; ///< Our dedicated pool +}; + + +//////////////////////////////////////////////////////////// +PoolWrapper::PoolWrapper() : +m_count(0), +m_pool(0) +{ + /* Nothing else */ +} + + +//////////////////////////////////////////////////////////// +PoolWrapper::~PoolWrapper() +{ +#ifdef SFML_DEBUG + if (m_count < 0) + sf::err() << "~PoolWrapper : m_count is less than zero! " + "You called releasePool from a thread too many times." + << std::endl; + else if (m_count > 0) + sf::err() << "~PoolWrapper : m_count is greater than zero! " + "You called releasePool from a thread to few times." + << std::endl; + else // m_count == 0 + sf::err() << "~PoolWrapper is HAPPY!" << std::endl; +#endif +} + + +//////////////////////////////////////////////////////////// +void PoolWrapper::retain() +{ + // Increase counter. + ++m_count; + + // Allocate pool if required. + if (m_pool == 0) + m_pool = [[NSAutoreleasePool alloc] init]; + +#ifdef SFML_DEBUG + if (m_count <= 0) + sf::err() << "PoolWrapper::retain : m_count <= 0! " << std::endl; +#endif +} + + +//////////////////////////////////////////////////////////// +void PoolWrapper::release() +{ + // Decrease counter. + --m_count; + + // Drain pool if required. + if (m_count == 0) + drain(); + +#ifdef SFML_DEBUG + if (m_count < 0) + sf::err() << "PoolWrapper::release : m_count < 0! " << std::endl; +#endif +} + +void PoolWrapper::drain() +{ + [m_pool drain]; + m_pool = 0; + + if (m_count != 0) + m_pool = [[NSAutoreleasePool alloc] init]; +} + + +} // namespace priv + +} // namespace sf + +//////////////////////////////////////////////////////////// +// Private data +//////////////////////////////////////////////////////////// +namespace +{ + // This per-thread variable holds the current autorelease pool for each thread + sf::ThreadLocalPtr localPool; +} + + +//////////////////////////////////////////////////////////// +void retainPool(void) +{ + // First, Check that we have a valid PoolWrapper object in our local pool. + if (localPool == NULL) + localPool = new sf::priv::PoolWrapper(); + + // Then retains! + localPool->retain(); +} + + +//////////////////////////////////////////////////////////// +void releasePool(void) +{ + if (localPool != NULL) + localPool->release(); +#ifdef SFML_DEBUG + else + sf::err() << "releasePool : You must call retainPool at least once " + "in this thread before calling releasePool." + << std::endl; +#endif +} + + +//////////////////////////////////////////////////////////// +void drainPool() +{ + if (localPool != NULL) + localPool->drain(); +#ifdef SFML_DEBUG + else + sf::err() << "releasePool must be called at least one before drainPool" + << std::endl; +#endif +} + diff --git a/src/SFML/Window/OSX/InputImpl.mm b/src/SFML/Window/OSX/InputImpl.mm index ab0898004..eb24fd080 100644 --- a/src/SFML/Window/OSX/InputImpl.mm +++ b/src/SFML/Window/OSX/InputImpl.mm @@ -57,7 +57,7 @@ namespace priv //////////////////////////////////////////////////////////// SFOpenGLView* getSFOpenGLViewFromSFMLWindow(const Window& window) { - id nsHandle = (__bridge id)window.getSystemHandle(); + id nsHandle = (id)window.getSystemHandle(); // Get our SFOpenGLView from ... SFOpenGLView* view = nil; diff --git a/src/SFML/Window/OSX/SFApplication.m b/src/SFML/Window/OSX/SFApplication.m index a2f468d3a..d12f26e36 100644 --- a/src/SFML/Window/OSX/SFApplication.m +++ b/src/SFML/Window/OSX/SFApplication.m @@ -35,8 +35,6 @@ //////////////////////////////////////////////////////////// +(void)processEvent -{ -@autoreleasepool { [SFApplication sharedApplication]; // Make sure NSApp exists NSEvent* event = nil; @@ -48,7 +46,6 @@ { [NSApp sendEvent:event]; } -} // pool } @@ -66,17 +63,17 @@ // Application Menu (aka Apple Menu) NSMenuItem* appleItem = [mainMenu addItemWithTitle:@"" action:nil keyEquivalent:@""]; - NSMenu* appleMenu = [SFApplication createAppleMenu]; + NSMenu* appleMenu = [[SFApplication createAppleMenu] autorelease]; [appleItem setSubmenu:appleMenu]; // File Menu NSMenuItem* fileItem = [mainMenu addItemWithTitle:@"" action:nil keyEquivalent:@""]; - NSMenu* fileMenu = [SFApplication createFileMenu]; + NSMenu* fileMenu = [[SFApplication createFileMenu] autorelease]; [fileItem setSubmenu:fileMenu]; // Window menu NSMenuItem* windowItem = [mainMenu addItemWithTitle:@"" action:nil keyEquivalent:@""]; - NSMenu* windowMenu = [SFApplication createWindowMenu]; + NSMenu* windowMenu = [[SFApplication createWindowMenu] autorelease]; [windowItem setSubmenu:windowMenu]; [NSApp setWindowsMenu:windowMenu]; } @@ -123,7 +120,7 @@ [appleMenu addItem:[NSMenuItem separatorItem]]; // SERVICES - NSMenu* serviceMenu = [[NSMenu alloc] initWithTitle:@""]; + NSMenu* serviceMenu = [[[NSMenu alloc] initWithTitle:@""] autorelease]; NSMenuItem* serviceItem = [appleMenu addItemWithTitle:@"Services" action:nil keyEquivalent:@""]; @@ -177,6 +174,7 @@ action:@selector(performClose:) keyEquivalent:@"w"]; [fileMenu addItem:closeItem]; + [closeItem release]; return fileMenu; } @@ -201,6 +199,7 @@ action:@selector(performMiniaturize:) keyEquivalent:@"m"]; [windowMenu addItem:minimizeItem]; + [minimizeItem release]; // ZOOM [windowMenu addItemWithTitle:@"Zoom" diff --git a/src/SFML/Window/OSX/SFApplicationDelegate.h b/src/SFML/Window/OSX/SFApplicationDelegate.h index 05f89cfe3..ed0fd1781 100644 --- a/src/SFML/Window/OSX/SFApplicationDelegate.h +++ b/src/SFML/Window/OSX/SFApplicationDelegate.h @@ -50,10 +50,4 @@ //////////////////////////////////////////////////////////// -(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication; -//////////////////////////////////////////////////////////// -/// \brief Return a singleton instance of this class -/// -//////////////////////////////////////////////////////////// -+(id)instance; - @end diff --git a/src/SFML/Window/OSX/SFApplicationDelegate.m b/src/SFML/Window/OSX/SFApplicationDelegate.m index b15678973..c22b720b8 100644 --- a/src/SFML/Window/OSX/SFApplicationDelegate.m +++ b/src/SFML/Window/OSX/SFApplicationDelegate.m @@ -49,14 +49,6 @@ return YES; } -//////////////////////////////////////////////////////////// -+(id)instance -{ - static SFApplicationDelegate* singleton = nil; - if (singleton == nil) - singleton = [[SFApplicationDelegate alloc] init]; - return singleton; -} @end diff --git a/src/SFML/Window/OSX/SFContext.mm b/src/SFML/Window/OSX/SFContext.mm index 9989af70b..9b1cbd114 100644 --- a/src/SFML/Window/OSX/SFContext.mm +++ b/src/SFML/Window/OSX/SFContext.mm @@ -30,6 +30,8 @@ #include #include +#import + namespace sf { namespace priv @@ -41,6 +43,9 @@ SFContext::SFContext(SFContext* shared) : m_view(0), m_window(0) { + // Ask for a pool. + retainPool(); + // Create the context createContext(shared, VideoMode::getDesktopMode().bitsPerPixel, @@ -54,6 +59,9 @@ SFContext::SFContext(SFContext* shared, const ContextSettings& settings, m_view(0), m_window(0) { + // Ask for a pool. + retainPool(); + // Create the context. createContext(shared, bitsPerPixel, settings); @@ -72,6 +80,9 @@ m_window(0) // Ensure the process is setup in order to create a valid window. WindowImplCocoa::setUpProcess(); + // Ask for a pool. + retainPool(); + // Create the context. createContext(shared, VideoMode::getDesktopMode().bitsPerPixel, settings); @@ -89,15 +100,14 @@ m_window(0) //////////////////////////////////////////////////////////// SFContext::~SFContext() -{ -@autoreleasepool { [m_context clearDrawable]; + [m_context release]; - m_context = nil; - m_view = nil; - m_window = nil; -} // pool + [m_view release]; // Might be nil but we don't care. + [m_window release]; // Idem. + + releasePool(); } @@ -129,8 +139,6 @@ void SFContext::setVerticalSyncEnabled(bool enabled) void SFContext::createContext(SFContext* shared, unsigned int bitsPerPixel, const ContextSettings& settings) -{ -@autoreleasepool { // Choose the attributes of OGL context. std::vector attrs; @@ -231,9 +239,11 @@ void SFContext::createContext(SFContext* shared, sf::err() << "Warning. New context created without shared context." << std::endl; } + // Free up. + [pixFmt release]; + // Save the settings. (OpenGL version is updated elsewhere.) m_settings = settings; -} // pool } } // namespace priv diff --git a/src/SFML/Window/OSX/SFOpenGLView.mm b/src/SFML/Window/OSX/SFOpenGLView.mm index 352f2169c..532a890c4 100644 --- a/src/SFML/Window/OSX/SFOpenGLView.mm +++ b/src/SFML/Window/OSX/SFOpenGLView.mm @@ -286,11 +286,14 @@ BOOL isValidTextUnicode(NSEvent* event); // Unregister [self removeTrackingArea:m_trackingArea]; + // Release attributes + [m_hiddenTextView release]; + [m_silentResponder release]; + [m_trackingArea release]; + [self setRequesterTo:0]; - m_hiddenTextView = nil; - m_silentResponder = nil; - m_trackingArea = nil; + [super dealloc]; } diff --git a/src/SFML/Window/OSX/SFViewController.mm b/src/SFML/Window/OSX/SFViewController.mm index 05e9dc941..bcb14efc3 100644 --- a/src/SFML/Window/OSX/SFViewController.mm +++ b/src/SFML/Window/OSX/SFViewController.mm @@ -44,7 +44,7 @@ m_requester = 0; // Retain the view for our own use. - m_view = view; + m_view = [view retain]; if (m_view == nil) { @@ -82,8 +82,10 @@ { [self closeWindow]; - m_view = nil; - m_oglView = nil; + [m_view release]; + [m_oglView release]; + + [super dealloc]; } @@ -99,7 +101,7 @@ //////////////////////////////////////////////////////// -(sf::WindowHandle)getSystemHandle { - return (__bridge sf::WindowHandle)m_view; + return m_view; } diff --git a/src/SFML/Window/OSX/SFWindowController.mm b/src/SFML/Window/OSX/SFWindowController.mm index 25e8ab13a..b5f0343ee 100644 --- a/src/SFML/Window/OSX/SFWindowController.mm +++ b/src/SFML/Window/OSX/SFWindowController.mm @@ -97,7 +97,7 @@ m_fullscreen = NO; // Retain the window for our own use. - m_window = window; + m_window = [window retain]; if (m_window == nil) { @@ -181,7 +181,7 @@ [m_window setOpaque:YES]; [m_window setHidesOnDeactivate:YES]; [m_window setAutodisplay:YES]; - [m_window setReleasedWhenClosed:YES]; + [m_window setReleasedWhenClosed:NO]; // We own the class, not AppKit // Register for event [m_window setDelegate:self]; @@ -287,7 +287,7 @@ // And some other things... [m_window center]; [m_window setAutodisplay:YES]; - [m_window setReleasedWhenClosed:YES]; + [m_window setReleasedWhenClosed:NO]; // We own the class, not AppKit } @@ -297,8 +297,10 @@ [self closeWindow]; [NSMenu setMenuBarVisible:YES]; - m_window = nil; - m_oglView = nil; + [m_window release]; + [m_oglView release]; + + [super dealloc]; } @@ -318,7 +320,7 @@ //////////////////////////////////////////////////////// -(sf::WindowHandle)getSystemHandle { - return (__bridge sf::WindowHandle)m_window; + return m_window; } @@ -442,6 +444,7 @@ //////////////////////////////////////////////////////// -(void)closeWindow { + [self applyContext:nil]; [m_window close]; [m_window setDelegate:nil]; [self setRequesterTo:0]; @@ -497,6 +500,10 @@ // Set app icon. [[SFApplication sharedApplication] setApplicationIconImage:icon]; + + // Free up. + [icon release]; + [bitmap release]; } diff --git a/src/SFML/Window/OSX/WindowImplCocoa.mm b/src/SFML/Window/OSX/WindowImplCocoa.mm index 6c7728005..93608c823 100644 --- a/src/SFML/Window/OSX/WindowImplCocoa.mm +++ b/src/SFML/Window/OSX/WindowImplCocoa.mm @@ -30,6 +30,7 @@ #include #include +#import #import #import #import @@ -109,10 +110,11 @@ void scaleOutXY(T& out) WindowImplCocoa::WindowImplCocoa(WindowHandle handle) : m_showCursor(true) { -@autoreleasepool -{ + // Ask for a pool. + retainPool(); + // Treat the handle as it real type - id nsHandle = (__bridge id)handle; + id nsHandle = (id)handle; if ([nsHandle isKindOfClass:[NSWindow class]]) { // We have a window. @@ -140,7 +142,6 @@ m_showCursor(true) // Finally, set up keyboard helper initialiseKeyboardHelper(); -} // pool } @@ -150,12 +151,13 @@ WindowImplCocoa::WindowImplCocoa(VideoMode mode, unsigned long style, const ContextSettings& /*settings*/) : m_showCursor(true) -{ -@autoreleasepool { // Transform the app process. setUpProcess(); + // Ask for a pool. + retainPool(); + // Use backing size scaleInWidthHeight(mode); @@ -165,23 +167,26 @@ m_showCursor(true) // Finally, set up keyboard helper initialiseKeyboardHelper(); -} // pool } //////////////////////////////////////////////////////////// WindowImplCocoa::~WindowImplCocoa() -{ -@autoreleasepool { [m_delegate closeWindow]; - m_delegate = nil; + + [m_delegate release]; // Put the next window in front, if any. NSArray* windows = [NSApp orderedWindows]; if ([windows count] > 0) [[windows objectAtIndex:0] makeKeyAndOrderFront:nil]; -} // pool + + releasePool(); + + drainPool(); // Make sure everything was freed + // This solve some issue when sf::Window::Create is called for the + // second time (nothing was render until the function was called again) } @@ -212,7 +217,7 @@ void WindowImplCocoa::setUpProcess(void) // Register an application delegate if there is none if (![[SFApplication sharedApplication] delegate]) - [NSApp setDelegate:[SFApplicationDelegate instance]]; + [NSApp setDelegate:[[SFApplicationDelegate alloc] init]]; // Create menus for the application (before finishing launching!) [SFApplication setUpMenuBar]; diff --git a/src/SFML/Window/OSX/cpp_objc_conversion.mm b/src/SFML/Window/OSX/cpp_objc_conversion.mm index 4c93aa5f8..6ce8a9b5b 100644 --- a/src/SFML/Window/OSX/cpp_objc_conversion.mm +++ b/src/SFML/Window/OSX/cpp_objc_conversion.mm @@ -54,5 +54,5 @@ NSString* sfStringToNSString(const sf::String& string) encoding = NSUTF32BigEndianStringEncoding; NSString* str = [[NSString alloc] initWithBytes:data length:length encoding:encoding]; - return str; + return [str autorelease]; }