Add @autoreleasepool blocks to the macOS specific files.

Without these blocks the strings aren't released until the thread that created them is closed, which means file accesses especially leak memory.

Also refocus the game when closing the keybindings window on macOS.
This commit is contained in:
Wayward Heart 2024-06-12 04:04:18 -05:00
parent a73f9ccc1f
commit 2622a84c53
4 changed files with 92 additions and 65 deletions

View file

@ -97,6 +97,7 @@ typedef NSMutableArray<NSNumber*> BindingIndexArray;
-(void)closeWindow {
[self setNotListening:true];
[_window close];
SDL_RaiseWindow(shState->rtData().window);
}
-(SettingsMenu*)setWindow:(NSWindow*)window {

View file

@ -118,7 +118,9 @@ MKXPZTouchBar *_sharedTouchBar;
if (fpsLabel) {
int targetFrameRate = shState->graphics().getFrameRate();
dispatch_async(dispatch_get_main_queue(), ^{
self->fpsLabel.stringValue = [NSString stringWithFormat:@"%@\n%i FPS (%i%%)", self.gameTitle, value, (int)((float)value / (float)targetFrameRate * 100)];
@autoreleasepool {
self->fpsLabel.stringValue = [NSString stringWithFormat:@"%@\n%i FPS (%i%%)", self.gameTitle, value, (int)((float)value / (float)targetFrameRate * 100)];
}
});
}
}

View file

@ -18,43 +18,54 @@
#define NSTOPATH(str) [NSFileManager.defaultManager fileSystemRepresentationWithPath:str]
bool filesystemImpl::fileExists(const char *path) {
BOOL isDir;
return [NSFileManager.defaultManager fileExistsAtPath:PATHTONS(path) isDirectory: &isDir] && !isDir;
@autoreleasepool{
BOOL isDir;
return [NSFileManager.defaultManager fileExistsAtPath:PATHTONS(path) isDirectory: &isDir] && !isDir;
}
}
std::string filesystemImpl::contentsOfFileAsString(const char *path) {
NSString *fileContents = [NSString stringWithContentsOfFile: PATHTONS(path)];
if (fileContents == nil)
throw Exception(Exception::NoFileError, "Failed to read file at %s", path);
return std::string(fileContents.UTF8String);
@autoreleasepool {
NSString *fileContents = [NSString stringWithContentsOfFile: PATHTONS(path)];
if (fileContents == nil)
throw Exception(Exception::NoFileError, "Failed to read file at %s", path);
return std::string(fileContents.UTF8String);
}
}
bool filesystemImpl::setCurrentDirectory(const char *path) {
return [NSFileManager.defaultManager changeCurrentDirectoryPath: PATHTONS(path)];
@autoreleasepool {
return [NSFileManager.defaultManager changeCurrentDirectoryPath: PATHTONS(path)];
}
}
std::string filesystemImpl::getCurrentDirectory() {
return std::string(NSTOPATH(NSFileManager.defaultManager.currentDirectoryPath));
@autoreleasepool {
return std::string(NSTOPATH(NSFileManager.defaultManager.currentDirectoryPath));
}
}
std::string filesystemImpl::normalizePath(const char *path, bool preferred, bool absolute) {
NSString *nspath = [NSURL fileURLWithPath: PATHTONS(path)].URLByStandardizingPath.path;
NSString *pwd = [NSString stringWithFormat:@"%@/", NSFileManager.defaultManager.currentDirectoryPath];
if (!absolute) {
nspath = [nspath stringByReplacingOccurrencesOfString:pwd withString:@""];
@autoreleasepool {
NSString *nspath = [NSURL fileURLWithPath: PATHTONS(path)].URLByStandardizingPath.path;
NSString *pwd = [NSString stringWithFormat:@"%@/", NSFileManager.defaultManager.currentDirectoryPath];
if (!absolute) {
nspath = [nspath stringByReplacingOccurrencesOfString:pwd withString:@""];
}
nspath = [nspath stringByReplacingOccurrencesOfString:@"\\" withString:@"/"];
return std::string(NSTOPATH(nspath));
}
nspath = [nspath stringByReplacingOccurrencesOfString:@"\\" withString:@"/"];
return std::string(NSTOPATH(nspath));
}
std::string filesystemImpl::getDefaultGameRoot() {
NSString *p = [NSString stringWithFormat: @"%@/%s", NSBundle.mainBundle.bundlePath, "Contents/Game"];
return std::string(NSTOPATH(p));
@autoreleasepool {
NSString *p = [NSString stringWithFormat: @"%@/%s", NSBundle.mainBundle.bundlePath, "Contents/Game"];
return std::string(NSTOPATH(p));
}
}
NSString *getPathForAsset_internal(const char *baseName, const char *ext) {
@ -73,51 +84,58 @@ NSString *getPathForAsset_internal(const char *baseName, const char *ext) {
}
std::string filesystemImpl::getPathForAsset(const char *baseName, const char *ext) {
NSString *assetPath = getPathForAsset_internal(baseName, ext);
if (assetPath == nil)
throw Exception(Exception::NoFileError, "Failed to find the asset named %s.%s", baseName, ext);
return std::string(NSTOPATH(getPathForAsset_internal(baseName, ext)));
@autoreleasepool {
NSString *assetPath = getPathForAsset_internal(baseName, ext);
if (assetPath == nil)
throw Exception(Exception::NoFileError, "Failed to find the asset named %s.%s", baseName, ext);
return std::string(NSTOPATH(getPathForAsset_internal(baseName, ext)));
}
}
std::string filesystemImpl::contentsOfAssetAsString(const char *baseName, const char *ext) {
NSString *path = getPathForAsset_internal(baseName, ext);
NSString *fileContents = [NSString stringWithContentsOfFile: path];
// This should never fail
if (fileContents == nil)
throw Exception(Exception::MKXPError, "Failed to read file at %s", path.UTF8String);
return std::string(fileContents.UTF8String);
@autoreleasepool {
NSString *path = getPathForAsset_internal(baseName, ext);
NSString *fileContents = [NSString stringWithContentsOfFile: path];
// This should never fail
if (fileContents == nil)
throw Exception(Exception::MKXPError, "Failed to read file at %s", path.UTF8String);
return std::string(fileContents.UTF8String);
}
}
std::string filesystemImpl::getResourcePath() {
return std::string(NSTOPATH(NSBundle.mainBundle.resourcePath));
@autoreleasepool {
return std::string(NSTOPATH(NSBundle.mainBundle.resourcePath));
}
}
std::string filesystemImpl::selectPath(SDL_Window *win, const char *msg, const char *prompt) {
NSOpenPanel *panel = [NSOpenPanel openPanel];
panel.canChooseDirectories = true;
panel.canChooseFiles = false;
if (msg) panel.message = @(msg);
if (prompt) panel.prompt = @(prompt);
//panel.directoryURL = [NSURL fileURLWithPath:NSFileManager.defaultManager.currentDirectoryPath];
SDL_SysWMinfo windowinfo{};
SDL_GetWindowWMInfo(win, &windowinfo);
[panel beginSheetModalForWindow:windowinfo.info.cocoa.window completionHandler:^(NSModalResponse res){
[NSApp stopModalWithCode:res];
}];
[NSApp runModalForWindow:windowinfo.info.cocoa.window];
// The window needs to be brought to the front again after the OpenPanel closes
[windowinfo.info.cocoa.window makeKeyAndOrderFront:nil];
if (panel.URLs.count > 0)
return std::string(NSTOPATH(panel.URLs[0].path));
return std::string();
@autoreleasepool {
NSOpenPanel *panel = [NSOpenPanel openPanel];
panel.canChooseDirectories = true;
panel.canChooseFiles = false;
if (msg) panel.message = @(msg);
if (prompt) panel.prompt = @(prompt);
//panel.directoryURL = [NSURL fileURLWithPath:NSFileManager.defaultManager.currentDirectoryPath];
SDL_SysWMinfo windowinfo{};
SDL_GetWindowWMInfo(win, &windowinfo);
[panel beginSheetModalForWindow:windowinfo.info.cocoa.window completionHandler:^(NSModalResponse res){
[NSApp stopModalWithCode:res];
}];
[NSApp runModalForWindow:windowinfo.info.cocoa.window];
// The window needs to be brought to the front again after the OpenPanel closes
[windowinfo.info.cocoa.window makeKeyAndOrderFront:nil];
if (panel.URLs.count > 0)
return std::string(NSTOPATH(panel.URLs[0].path));
return std::string();
}
}

View file

@ -13,13 +13,17 @@
#import "SettingsMenuController.h"
std::string systemImpl::getSystemLanguage() {
NSString *languageCode = NSLocale.currentLocale.languageCode;
NSString *countryCode = NSLocale.currentLocale.countryCode;
return std::string([NSString stringWithFormat:@"%@_%@", languageCode, countryCode].UTF8String);
@autoreleasepool {
NSString *languageCode = NSLocale.currentLocale.languageCode;
NSString *countryCode = NSLocale.currentLocale.countryCode;
return std::string([NSString stringWithFormat:@"%@_%@", languageCode, countryCode].UTF8String);
}
}
std::string systemImpl::getUserName() {
return std::string(NSUserName().UTF8String);
@autoreleasepool {
return std::string(NSUserName().UTF8String);
}
}
int systemImpl::getScalingFactor() {
@ -64,9 +68,11 @@ bool isMetalSupported() {
}
std::string getPlistValue(const char *key) {
NSString *hash = [[NSBundle mainBundle] objectForInfoDictionaryKey:@(key)];
if (hash != nil) {
return std::string(hash.UTF8String);
@autoreleasepool {
NSString *hash = [[NSBundle mainBundle] objectForInfoDictionaryKey:@(key)];
if (hash != nil) {
return std::string(hash.UTF8String);
}
return "";
}
return "";
}