Reverted OS X implementation to non-ARC

* Apparently, there were some leaks not reported as such
 * Support for 32 bits computer is restored
 * Fix memory leak in sfStringToNSString (related to #484)
 * Unapply context when closing the window, freeing memory

The following commits are related to ARC modifications:

 * 42f6e83dfb
 * 6edc4b9518
 * f6c94451fb
 * 324d4a18e7
 * 0d47056132

Commit ac28902b57 is the last one before the introduction of ARC.
This commit is contained in:
Marco Antognini 2014-05-17 11:23:11 +02:00
parent a8ab8fb061
commit b9f5f19f7c
15 changed files with 347 additions and 71 deletions

View File

@ -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")

View File

@ -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})

View File

@ -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)

View File

@ -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();

View File

@ -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 <SFML/System/Err.hpp>
#include <SFML/System/NonCopyable.hpp>
#include <SFML/System/ThreadLocalPtr.hpp>
#import <SFML/Window/OSX/AutoreleasePoolWrapper.h>
#import <Foundation/Foundation.h>
////////////////////////////////////////////////////////////
/// 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<sf::priv::PoolWrapper> 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
}

View File

@ -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;

View File

@ -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"

View File

@ -50,10 +50,4 @@
////////////////////////////////////////////////////////////
-(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication;
////////////////////////////////////////////////////////////
/// \brief Return a singleton instance of this class
///
////////////////////////////////////////////////////////////
+(id)instance;
@end

View File

@ -49,14 +49,6 @@
return YES;
}
////////////////////////////////////////////////////////////
+(id)instance
{
static SFApplicationDelegate* singleton = nil;
if (singleton == nil)
singleton = [[SFApplicationDelegate alloc] init];
return singleton;
}
@end

View File

@ -30,6 +30,8 @@
#include <SFML/Window/OSX/WindowImplCocoa.hpp>
#include <SFML/System/Err.hpp>
#import <SFML/Window/OSX/AutoreleasePoolWrapper.h>
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<NSOpenGLPixelFormatAttribute> 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

View File

@ -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];
}

View File

@ -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;
}

View File

@ -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];
}

View File

@ -30,6 +30,7 @@
#include <SFML/System/Err.hpp>
#include <SFML/System/String.hpp>
#import <SFML/Window/OSX/AutoreleasePoolWrapper.h>
#import <SFML/Window/OSX/cpp_objc_conversion.h>
#import <SFML/Window/OSX/SFApplication.h>
#import <SFML/Window/OSX/SFApplicationDelegate.h>
@ -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];

View File

@ -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];
}