(Apple) Split platform specific code out of main.m

This commit is contained in:
meancoot 2013-08-14 10:07:36 -04:00
parent 7236e51af0
commit 4f70bdeab5
9 changed files with 767 additions and 658 deletions

42
apple/OSX/platform.h Normal file
View File

@ -0,0 +1,42 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2013 - Jason Fetters
* Copyright (C) 2011-2013 - Daniel De Matteis
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __RARCH_OSX_PLATFORM_H
#define __RARCH_OSX_PLATFORM_H
#import <AppKit/AppKit.h>
@interface RAGameView : NSOpenGLView
+ (RAGameView*)get;
- (void)display;
@end
@interface RetroArch_OSX : NSObject<RetroArch_Platform, NSApplicationDelegate>
{
@public
NSWindow IBOutlet *window;
}
+ (RetroArch_OSX*)get;
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file;
- (void)unloadingCore:(RAModuleInfo*)core;
@end
#endif

264
apple/OSX/platform.m Normal file
View File

@ -0,0 +1,264 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2013 - Jason Fetters
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <pthread.h>
#include <string.h>
#import "RetroArch_Apple.h"
#include "rarch_wrapper.h"
#include "../RetroArch/apple_input.h"
// If USE_XATTR is defined any loaded file will get a com.RetroArch.Core extended attribute
// specifying which core was used to load.
//#define USE_XATTR
#if defined(USE_XATTR)
#include "sys/xattr.h"
#endif
#include "file.h"
@interface RApplication : NSApplication
@end
@implementation RApplication
- (void)sendEvent:(NSEvent *)event
{
[super sendEvent:event];
if (event.type == GSEVENT_TYPE_KEYDOWN || event.type == GSEVENT_TYPE_KEYUP)
apple_input_handle_key_event(event.keyCode, event.type == GSEVENT_TYPE_KEYDOWN);
}
@end
@implementation RetroArch_OSX
{
NSWindow IBOutlet* _coreSelectSheet;
bool _isTerminating;
bool _loaded;
bool _wantReload;
NSString* _file;
RAModuleInfo* _core;
}
+ (RetroArch_OSX*)get
{
return (RetroArch_OSX*)[[NSApplication sharedApplication] delegate];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
apple_platform = self;
_loaded = true;
[window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
RAGameView.get.frame = [window.contentView bounds];
[window.contentView setAutoresizesSubviews:YES];
[window.contentView addSubview:RAGameView.get];
[window makeFirstResponder:RAGameView.get];
// Create core select list
NSComboBox* cb = (NSComboBox*)[_coreSelectSheet.contentView viewWithTag:1];
for (RAModuleInfo* i in RAModuleInfo.getModules)
[cb addItemWithObjectValue:i];
if (cb.numberOfItems)
[cb selectItemAtIndex:0];
else
apple_display_alert(@"No libretro cores were found.", @"RetroArch");
// Run RGUI if needed
if (!_wantReload)
apple_run_core(nil, 0);
else
[self chooseCore];
_wantReload = false;
extern void osx_pad_init();
osx_pad_init();
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
{
return YES;
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
_isTerminating = true;
if (apple_is_running)
apple_frontend_post_event(apple_event_basic_command, (void*)QUIT);
return apple_is_running ? NSTerminateCancel : NSTerminateNow;
}
- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
{
if (filenames.count == 1 && filenames[0])
{
_file = filenames[0];
if (!_loaded)
_wantReload = true;
else
[self chooseCore];
[sender replyToOpenOrPrint:NSApplicationDelegateReplySuccess];
}
else
{
apple_display_alert(@"Cannot open multiple files", @"RetroArch");
[sender replyToOpenOrPrint:NSApplicationDelegateReplyFailure];
}
}
- (void)openDocument:(id)sender
{
NSOpenPanel* panel = [NSOpenPanel openPanel];
[panel beginSheetModalForWindow:window completionHandler:^(NSInteger result)
{
[NSApplication.sharedApplication stopModal];
if (result == NSOKButton && panel.URL)
{
_file = panel.URL.path;
[self performSelector:@selector(chooseCore) withObject:nil afterDelay:.5f];
}
}];
[NSApplication.sharedApplication runModalForWindow:panel];
}
// This utility function will queue the _core and _file instance values for running.
// If the emulator thread is already running it will tell it to quit.
- (void)runCore
{
_wantReload = apple_is_running;
if (!apple_is_running)
apple_run_core(_core, _file.UTF8String);
else
apple_frontend_post_event(apple_event_basic_command, (void*)QUIT);
}
- (void)chooseCore
{
#ifdef USE_XATTR
char stored_name[PATH_MAX];
if (getxattr(_file.UTF8String, "com.RetroArch.Core", stored_name, PATH_MAX, 0, 0) > 0)
{
for (RAModuleInfo* i in RAModuleInfo.getModules)
{
const char* core_name = i.path.lastPathComponent.UTF8String;
if (strcmp(core_name, stored_name) == 0)
{
_core = i;
[self runCore];
return;
}
}
}
#endif
[NSApplication.sharedApplication beginSheet:_coreSelectSheet modalForWindow:window modalDelegate:nil didEndSelector:nil contextInfo:nil];
[NSApplication.sharedApplication runModalForWindow:_coreSelectSheet];
}
- (IBAction)coreWasChosen:(id)sender
{
[NSApplication.sharedApplication stopModal];
[NSApplication.sharedApplication endSheet:_coreSelectSheet returnCode:0];
[_coreSelectSheet orderOut:self];
if (_isTerminating)
return;
NSComboBox* cb = (NSComboBox*)[_coreSelectSheet.contentView viewWithTag:1];
_core = (RAModuleInfo*)cb.objectValueOfSelectedItem;
[self runCore];
}
#pragma mark RetroArch_Platform
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file
{
if (file)
{
[NSDocumentController.sharedDocumentController noteNewRecentDocumentURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:file]]];
#ifdef USE_XATTR
const char* core_name = core.path.lastPathComponent.UTF8String;
setxattr(file, "com.RetroArch.Core", core_name, strlen(core_name) + 1, 0, 0);
#endif
}
}
- (void)unloadingCore:(RAModuleInfo*)core
{
if (_isTerminating)
[NSApplication.sharedApplication terminate:nil];
if (_wantReload)
apple_run_core(_core, _file.UTF8String);
else if(apple_use_tv_mode)
apple_run_core(nil, 0);
else
[NSApplication.sharedApplication terminate:nil];
_wantReload = false;
}
- (NSString*)retroarchConfigPath
{
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
return [paths[0] stringByAppendingPathComponent:@"RetroArch/retroarch.cfg"];
}
- (NSString*)corePath
{
return [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"Contents/Resources/modules"];
}
#pragma mark Menus
- (IBAction)showPreferences:(id)sender
{
[[[NSWindowController alloc] initWithWindowNibName:@"Settings"] window];
}
- (IBAction)basicEvent:(id)sender
{
if (apple_is_running)
apple_frontend_post_event(&apple_event_basic_command, (void*)((NSMenuItem*)sender).tag);
}
- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
{
[NSApplication.sharedApplication stopModal];
}
@end
int main(int argc, char *argv[])
{
return NSApplicationMain(argc, (const char **) argv);
}

View File

@ -21,7 +21,8 @@
#import <CoreFoundation/CoreFoundation.h>
#import "RAModuleInfo.h"
void apple_run_core(RAModuleInfo* core, const char* file);
#define GSEVENT_TYPE_KEYDOWN 10
#define GSEVENT_TYPE_KEYUP 11
@protocol RetroArch_Platform
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file;
@ -30,59 +31,29 @@ void apple_run_core(RAModuleInfo* core, const char* file);
- (NSString*)corePath;
@end
#ifdef IOS
#import "../iOS/platform.h"
#elif defined(OSX)
#import "../OSX/platform.h"
#endif
extern bool apple_is_paused;
extern bool apple_is_running;
extern bool apple_use_tv_mode;
extern RAModuleInfo* apple_core;
extern id<RetroArch_Platform> apple_platform;
#ifdef IOS
// main.m
enum basic_event_t { RESET = 1, LOAD_STATE = 2, SAVE_STATE = 3, QUIT = 4 };
extern void apple_event_basic_command(void* userdata);
extern void apple_event_set_state_slot(void* userdata);
extern void apple_event_show_rgui(void* userdata);
// RAGameView.m
@interface RAGameView : UIViewController
+ (RAGameView*)get;
- (void)openPauseMenu;
- (void)closePauseMenu;
@end
@interface RetroArch_iOS : UINavigationController<UIApplicationDelegate, UINavigationControllerDelegate, RetroArch_Platform>
+ (RetroArch_iOS*)get;
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file;
- (void)unloadingCore:(RAModuleInfo*)core;
- (NSString*)retroarchConfigPath;
- (void)refreshConfig;
- (void)refreshSystemConfig;
@property (strong, nonatomic) NSString* documentsDirectory; // e.g. /var/mobile/Documents
@property (strong, nonatomic) NSString* systemDirectory; // e.g. /var/mobile/Documents/.RetroArch
@property (strong, nonatomic) NSString* systemConfigPath; // e.g. /var/mobile/Documents/.RetroArch/frontend.cfg
@end
#elif defined(OSX)
#import <AppKit/AppKit.h>
@interface RAGameView : NSOpenGLView
+ (RAGameView*)get;
- (void)display;
@end
@interface RetroArch_OSX : NSObject<RetroArch_Platform, NSApplicationDelegate>
{
@public
NSWindow IBOutlet *window;
}
+ (RetroArch_OSX*)get;
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file;
- (void)unloadingCore:(RAModuleInfo*)core;
@end
#endif
extern void apple_refresh_config();
extern void apple_enter_stasis();
extern void apple_exit_stasis();
extern void apple_run_core(RAModuleInfo* core, const char* file);
// utility.m
extern void apple_display_alert(NSString* message, NSString* title);
@ -90,4 +61,7 @@ extern void objc_clear_config_hack();
extern bool path_make_and_check_directory(const char* path, mode_t mode, int amode);
extern NSString* objc_get_value_from_config(config_file_t* config, NSString* name, NSString* defaultValue);
// frontend/platform/platform_apple.c
extern void apple_frontend_post_event(void (*fn)(void*), void* userdata);
#endif

View File

@ -21,36 +21,14 @@
#include "apple_input.h"
// If USE_XATTR is defined any loaded file will get a com.RetroArch.Core extended attribute
// specifying which core was used to load.
//#define USE_XATTR
#ifdef IOS
#import "views.h"
#include "../iOS/input/BTStack/btpad.h"
#include "../iOS/input/BTStack/btdynamic.h"
#include "../iOS/input/BTStack/btpad.h"
#elif defined(USE_XATTR)
#include "sys/xattr.h"
#endif
#include "file.h"
#define GSEVENT_TYPE_KEYDOWN 10
#define GSEVENT_TYPE_KEYUP 11
//#define HAVE_DEBUG_FILELOG
static bool use_tv_mode;
id<RetroArch_Platform> apple_platform;
// From frontend/frontend_ios.c
extern void apple_frontend_post_event(void (*fn)(void*), void* userdata);
// These are based on the tag property of the button used to trigger the event
enum basic_event_t { RESET = 1, LOAD_STATE = 2, SAVE_STATE = 3, QUIT = 4 };
static void event_basic_command(void* userdata)
void apple_event_basic_command(void* userdata)
{
switch ((enum basic_event_t)userdata)
{
@ -61,12 +39,12 @@ static void event_basic_command(void* userdata)
}
}
static void event_set_state_slot(void* userdata)
void apple_event_set_state_slot(void* userdata)
{
g_extern.state_slot = (uint32_t)userdata;
}
static void event_show_rgui(void* userdata)
void apple_event_show_rgui(void* userdata)
{
const bool in_menu = g_extern.lifecycle_mode_state & (1 << MODE_MENU);
g_extern.lifecycle_mode_state &= ~(1ULL << (in_menu ? MODE_MENU : MODE_GAME));
@ -82,7 +60,15 @@ static void event_reload_config(void* userdata)
init_drivers();
}
static pthread_mutex_t stasis_mutex = PTHREAD_MUTEX_INITIALIZER;
void apple_refresh_config()
{
if (apple_is_running)
apple_frontend_post_event(&event_reload_config, 0);
else
objc_clear_config_hack();
}
pthread_mutex_t stasis_mutex = PTHREAD_MUTEX_INITIALIZER;
static void event_stasis(void* userdata)
{
@ -94,18 +80,34 @@ static void event_stasis(void* userdata)
init_drivers();
}
void apple_enter_stasis()
{
if (apple_is_running)
{
pthread_mutex_lock(&stasis_mutex);
apple_frontend_post_event(event_stasis, 0);
}
}
void apple_exit_stasis()
{
if (apple_is_running)
pthread_mutex_unlock(&stasis_mutex);
}
#pragma mark EMULATION
static pthread_t apple_retro_thread;
static bool apple_is_paused;
static bool apple_is_running;
static RAModuleInfo* apple_core;
bool apple_is_paused;
bool apple_is_running;
bool apple_use_tv_mode;
RAModuleInfo* apple_core;
void* rarch_main_spring(void* args)
{
char** argv = args;
uint32_t argc = 0;
while (argv && argv[argc ++]);
while (argv && argv[argc]) argc++;
if (rarch_main(argc, argv))
{
@ -136,11 +138,15 @@ void apple_run_core(RAModuleInfo* core, const char* file)
if (file && core)
{
argv[3] = "-L";
argv[4] = core_path;
strlcpy(core_path, apple_core.path.UTF8String, sizeof(core_path));
strlcpy(file_path, file, sizeof(file_path));
}
else
argv[3] = 0;
{
argv[3] = "--menu";
argv[4] = 0;
}
if (pthread_create(&apple_retro_thread, 0, rarch_main_spring, argv))
{
@ -169,578 +175,3 @@ void apple_rarch_exited(void* result)
if (use_tv_mode)
apple_run_core(nil, 0);
}
//
// IOS
//
#pragma mark IOS
#ifdef IOS
// Input helpers: This is kept here because it needs objective-c
static void handle_touch_event(NSArray* touches)
{
const int numTouches = [touches count];
const float scale = [[UIScreen mainScreen] scale];
g_current_input_data.touch_count = 0;
for(int i = 0; i != numTouches && g_current_input_data.touch_count < MAX_TOUCHES; i ++)
{
UITouch* touch = [touches objectAtIndex:i];
const CGPoint coord = [touch locationInView:touch.view];
if (touch.phase != UITouchPhaseEnded && touch.phase != UITouchPhaseCancelled)
{
g_current_input_data.touches[g_current_input_data.touch_count ].screen_x = coord.x * scale;
g_current_input_data.touches[g_current_input_data.touch_count ++].screen_y = coord.y * scale;
}
}
}
@interface RApplication : UIApplication
@end
@implementation RApplication
- (void)sendEvent:(UIEvent *)event
{
[super sendEvent:event];
if ([[event allTouches] count])
handle_touch_event(event.allTouches.allObjects);
else if ([event respondsToSelector:@selector(_gsEvent)])
{
// Stolen from: http://nacho4d-nacho4d.blogspot.com/2012/01/catching-keyboard-events-in-ios.html
uint8_t* eventMem = (uint8_t*)(void*)CFBridgingRetain([event performSelector:@selector(_gsEvent)]);
int eventType = eventMem ? *(int*)&eventMem[8] : 0;
if (eventType == GSEVENT_TYPE_KEYDOWN || eventType == GSEVENT_TYPE_KEYUP)
apple_input_handle_key_event(*(uint16_t*)&eventMem[0x3C], eventType == GSEVENT_TYPE_KEYDOWN);
CFBridgingRelease(eventMem);
}
}
int main(int argc, char *argv[])
{
@autoreleasepool {
#if defined(HAVE_DEBUG_FILELOG) && (TARGET_IPHONE_SIMULATOR == 0)
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *logPath = [documentsDirectory stringByAppendingPathComponent:@"console_stdout.log"];
freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding], "a", stdout);
freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding], "a", stderr);
#endif
return UIApplicationMain(argc, argv, NSStringFromClass([RApplication class]), NSStringFromClass([RetroArch_iOS class]));
}
}
@end
@implementation RetroArch_iOS
{
UIWindow* _window;
bool _isGameTop, _isRomList;
uint32_t _settingMenusInBackStack;
uint32_t _enabledOrientations;
RAModuleInfo* _module;
}
+ (RetroArch_iOS*)get
{
return (RetroArch_iOS*)[[UIApplication sharedApplication] delegate];
}
// UIApplicationDelegate
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
apple_platform = self;
self.delegate = self;
// Setup window
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
_window.rootViewController = self;
[_window makeKeyAndVisible];
// Build system paths and test permissions
self.documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
self.systemDirectory = [self.documentsDirectory stringByAppendingPathComponent:@".RetroArch"];
self.systemConfigPath = [self.systemDirectory stringByAppendingPathComponent:@"frontend.cfg"];
if (!path_make_and_check_directory(self.documentsDirectory.UTF8String, 0755, R_OK | W_OK | X_OK))
apple_display_alert([NSString stringWithFormat:@"Failed to create or access base directory: %@", self.documentsDirectory], 0);
else if (!path_make_and_check_directory(self.systemDirectory.UTF8String, 0755, R_OK | W_OK | X_OK))
apple_display_alert([NSString stringWithFormat:@"Failed to create or access system directory: %@", self.systemDirectory], 0);
else
{
[self pushViewController:[RADirectoryList directoryListAtBrowseRoot] animated:YES];
[self refreshSystemConfig];
if (use_tv_mode)
apple_run_core(nil, 0);
}
// Warn if there are no cores present
if ([RAModuleInfo getModules].count == 0)
apple_display_alert(@"No libretro cores were found. You will not be able to play any games.", 0);
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
if (apple_is_running)
pthread_mutex_unlock(&stasis_mutex);
}
- (void)applicationWillResignActive:(UIApplication *)application
{
if (apple_is_running)
{
pthread_mutex_lock(&stasis_mutex);
apple_frontend_post_event(event_stasis, 0);
}
}
// UINavigationControllerDelegate
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
_isGameTop = [viewController isKindOfClass:[RAGameView class]];
_isRomList = [viewController isKindOfClass:[RADirectoryList class]];
[[UIApplication sharedApplication] setStatusBarHidden:_isGameTop withAnimation:UIStatusBarAnimationNone];
[[UIApplication sharedApplication] setIdleTimerDisabled:_isGameTop];
self.navigationBarHidden = _isGameTop;
[self setToolbarHidden:!_isRomList animated:YES];
self.topViewController.navigationItem.rightBarButtonItem = [self createSettingsButton];
}
// UINavigationController: Never animate when pushing onto, or popping, an RAGameView
- (void)pushViewController:(UIViewController*)theView animated:(BOOL)animated
{
if ([theView respondsToSelector:@selector(isSettingsView)] && [(id)theView isSettingsView])
_settingMenusInBackStack ++;
[super pushViewController:theView animated:animated && !_isGameTop];
}
- (UIViewController*)popViewControllerAnimated:(BOOL)animated
{
if ([self.topViewController respondsToSelector:@selector(isSettingsView)] && [(id)self.topViewController isSettingsView])
_settingMenusInBackStack --;
return [super popViewControllerAnimated:animated && !_isGameTop];
}
// NOTE: This version only runs on iOS6
- (NSUInteger)supportedInterfaceOrientations
{
return _isGameTop ? _enabledOrientations
: UIInterfaceOrientationMaskAll;
}
// NOTE: This version runs on iOS2-iOS5, but not iOS6
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (_isGameTop)
switch (interfaceOrientation)
{
case UIInterfaceOrientationPortrait:
return (_enabledOrientations & UIInterfaceOrientationMaskPortrait);
case UIInterfaceOrientationPortraitUpsideDown:
return (_enabledOrientations & UIInterfaceOrientationMaskPortraitUpsideDown);
case UIInterfaceOrientationLandscapeLeft:
return (_enabledOrientations & UIInterfaceOrientationMaskLandscapeLeft);
case UIInterfaceOrientationLandscapeRight:
return (_enabledOrientations & UIInterfaceOrientationMaskLandscapeRight);
}
return YES;
}
#pragma mark RetroArch_Platform
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file
{
[self pushViewController:RAGameView.get animated:NO];
[RASettingsList refreshModuleConfig:core];
btpad_set_inquiry_state(false);
[self refreshSystemConfig];
}
- (void)unloadingCore:(RAModuleInfo*)core
{
[self popToViewController:[RAGameView get] animated:NO];
[self popViewControllerAnimated:NO];
btpad_set_inquiry_state(true);
}
- (NSString*)retroarchConfigPath
{
return [NSString stringWithFormat:@"%@/retroarch.cfg", self.systemDirectory];
}
- (NSString*)corePath
{
return [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"modules"];
}
- (void)refreshConfig
{
if (apple_is_running)
apple_frontend_post_event(&event_reload_config, 0);
else
objc_clear_config_hack();
}
- (void)refreshSystemConfig
{
// Read load time settings
config_file_t* conf = config_file_new([self.systemConfigPath UTF8String]);
if (conf)
{
// Get enabled orientations
static const struct { const char* setting; uint32_t orientation; } orientationSettings[4] =
{
{ "ios_allow_portrait", UIInterfaceOrientationMaskPortrait },
{ "ios_allow_portrait_upside_down", UIInterfaceOrientationMaskPortraitUpsideDown },
{ "ios_allow_landscape_left", UIInterfaceOrientationMaskLandscapeLeft },
{ "ios_allow_landscape_right", UIInterfaceOrientationMaskLandscapeRight }
};
_enabledOrientations = 0;
for (int i = 0; i < 4; i ++)
{
bool enabled = false;
bool found = config_get_bool(conf, orientationSettings[i].setting, &enabled);
if (!found || enabled)
_enabledOrientations |= orientationSettings[i].orientation;
}
// Setup bluetooth mode
NSString* btmode = objc_get_value_from_config(conf, @"ios_btmode", @"keyboard");
apple_input_enable_icade([btmode isEqualToString:@"icade"]);
btstack_set_poweron([btmode isEqualToString:@"btstack"]);
bool val;
use_tv_mode = config_get_bool(conf, "ios_tv_mode", & val) && val;
config_file_free(conf);
}
}
#pragma mark PAUSE MENU
- (UIBarButtonItem*)createSettingsButton
{
if (_settingMenusInBackStack == 0)
return [[UIBarButtonItem alloc]
initWithTitle:@"Settings"
style:UIBarButtonItemStyleBordered
target:[RetroArch_iOS get]
action:@selector(showSystemSettings)];
else
return nil;
}
- (IBAction)showPauseMenu:(id)sender
{
if (apple_is_running && !apple_is_paused && _isGameTop)
{
apple_is_paused = true;
[[RAGameView get] openPauseMenu];
btpad_set_inquiry_state(true);
}
}
- (IBAction)basicEvent:(id)sender
{
if (apple_is_running)
apple_frontend_post_event(&event_basic_command, ((UIView*)sender).tag);
[self closePauseMenu:sender];
}
- (IBAction)chooseState:(id)sender
{
if (apple_is_running)
apple_frontend_post_event(event_set_state_slot, (void*)((UISegmentedControl*)sender).selectedSegmentIndex);
}
- (IBAction)showRGUI:(id)sender
{
if (apple_is_running)
apple_frontend_post_event(event_show_rgui, 0);
[self closePauseMenu:sender];
}
- (IBAction)closePauseMenu:(id)sender
{
[[RAGameView get] closePauseMenu];
apple_is_paused = false;
btpad_set_inquiry_state(false);
}
- (IBAction)showSettings
{
[self pushViewController:[[RASettingsList alloc] initWithModule:_module] animated:YES];
}
- (IBAction)showSystemSettings
{
[self pushViewController:[RASystemSettingsList new] animated:YES];
}
@end
#endif
//
// OSX
//
#pragma mark OSX
#ifdef OSX
@interface RApplication : NSApplication
@end
@implementation RApplication
- (void)sendEvent:(NSEvent *)event
{
[super sendEvent:event];
if (event.type == GSEVENT_TYPE_KEYDOWN || event.type == GSEVENT_TYPE_KEYUP)
apple_input_handle_key_event(event.keyCode, event.type == GSEVENT_TYPE_KEYDOWN);
}
@end
@implementation RetroArch_OSX
{
NSWindow IBOutlet* _coreSelectSheet;
bool _isTerminating;
bool _loaded;
bool _wantReload;
NSString* _file;
RAModuleInfo* _core;
}
+ (RetroArch_OSX*)get
{
return (RetroArch_OSX*)[[NSApplication sharedApplication] delegate];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
apple_platform = self;
_loaded = true;
[window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
RAGameView.get.frame = [window.contentView bounds];
[window.contentView setAutoresizesSubviews:YES];
[window.contentView addSubview:RAGameView.get];
[window makeFirstResponder:RAGameView.get];
// Create core select list
NSComboBox* cb = (NSComboBox*)[_coreSelectSheet.contentView viewWithTag:1];
for (RAModuleInfo* i in RAModuleInfo.getModules)
[cb addItemWithObjectValue:i];
if (cb.numberOfItems)
[cb selectItemAtIndex:0];
else
apple_display_alert(@"No libretro cores were found.", @"RetroArch");
// Run RGUI if needed
if (!_wantReload)
apple_run_core(nil, 0);
else
[self chooseCore];
_wantReload = false;
extern void osx_pad_init();
osx_pad_init();
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
{
return YES;
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
_isTerminating = true;
if (apple_is_running)
apple_frontend_post_event(event_basic_command, (void*)QUIT);
return apple_is_running ? NSTerminateCancel : NSTerminateNow;
}
- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
{
if (filenames.count == 1 && filenames[0])
{
_file = filenames[0];
if (!_loaded)
_wantReload = true;
else
[self chooseCore];
[sender replyToOpenOrPrint:NSApplicationDelegateReplySuccess];
}
else
{
apple_display_alert(@"Cannot open multiple files", @"RetroArch");
[sender replyToOpenOrPrint:NSApplicationDelegateReplyFailure];
}
}
- (void)openDocument:(id)sender
{
NSOpenPanel* panel = [NSOpenPanel openPanel];
[panel beginSheetModalForWindow:window completionHandler:^(NSInteger result)
{
[NSApplication.sharedApplication stopModal];
if (result == NSOKButton && panel.URL)
{
_file = panel.URL.path;
[self performSelector:@selector(chooseCore) withObject:nil afterDelay:.5f];
}
}];
[NSApplication.sharedApplication runModalForWindow:panel];
}
// This utility function will queue the _core and _file instance values for running.
// If the emulator thread is already running it will tell it to quit.
- (void)runCore
{
_wantReload = apple_is_running;
if (!apple_is_running)
apple_run_core(_core, _file.UTF8String);
else
apple_frontend_post_event(event_basic_command, (void*)QUIT);
}
- (void)chooseCore
{
#ifdef USE_XATTR
char stored_name[PATH_MAX];
if (getxattr(_file.UTF8String, "com.RetroArch.Core", stored_name, PATH_MAX, 0, 0) > 0)
{
for (RAModuleInfo* i in RAModuleInfo.getModules)
{
const char* core_name = i.path.lastPathComponent.UTF8String;
if (strcmp(core_name, stored_name) == 0)
{
_core = i;
[self runCore];
return;
}
}
}
#endif
[NSApplication.sharedApplication beginSheet:_coreSelectSheet modalForWindow:window modalDelegate:nil didEndSelector:nil contextInfo:nil];
[NSApplication.sharedApplication runModalForWindow:_coreSelectSheet];
}
- (IBAction)coreWasChosen:(id)sender
{
[NSApplication.sharedApplication stopModal];
[NSApplication.sharedApplication endSheet:_coreSelectSheet returnCode:0];
[_coreSelectSheet orderOut:self];
if (_isTerminating)
return;
NSComboBox* cb = (NSComboBox*)[_coreSelectSheet.contentView viewWithTag:1];
_core = (RAModuleInfo*)cb.objectValueOfSelectedItem;
[self runCore];
}
#pragma mark RetroArch_Platform
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file
{
if (file)
{
[NSDocumentController.sharedDocumentController noteNewRecentDocumentURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:file]]];
#ifdef USE_XATTR
const char* core_name = core.path.lastPathComponent.UTF8String;
setxattr(file, "com.RetroArch.Core", core_name, strlen(core_name) + 1, 0, 0);
#endif
}
}
- (void)unloadingCore:(RAModuleInfo*)core
{
if (_isTerminating)
[NSApplication.sharedApplication terminate:nil];
if (_wantReload)
apple_run_core(_core, _file.UTF8String);
else if(use_tv_mode)
apple_run_core(nil, 0);
else
[NSApplication.sharedApplication terminate:nil];
_wantReload = false;
}
- (NSString*)retroarchConfigPath
{
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
return [paths[0] stringByAppendingPathComponent:@"RetroArch/retroarch.cfg"];
}
- (NSString*)corePath
{
return [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"Contents/Resources/modules"];
}
#pragma mark Menus
- (IBAction)showPreferences:(id)sender
{
[[[NSWindowController alloc] initWithWindowNibName:@"Settings"] window];
}
- (IBAction)basicEvent:(id)sender
{
if (apple_is_running)
apple_frontend_post_event(&event_basic_command, (void*)((NSMenuItem*)sender).tag);
}
- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
{
[NSApplication.sharedApplication stopModal];
}
@end
int main(int argc, char *argv[])
{
return NSApplicationMain(argc, (const char **) argv);
}
#endif

View File

@ -11,6 +11,7 @@
9620F6651790004F001B3B81 /* Settings.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9620F6641790004F001B3B81 /* Settings.xib */; };
962EE0E2178B3DF6004224FF /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 962EE0E1178B3DF6004224FF /* IOKit.framework */; };
96355CE31788E72A0010DBFA /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96355CE21788E72A0010DBFA /* Cocoa.framework */; };
9646869817BBC14E00C5EA69 /* platform.m in Sources */ = {isa = PBXBuildFile; fileRef = 9646869617BBC14E00C5EA69 /* platform.m */; };
967894931788ECDB00D6CA69 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9678948F1788ECDB00D6CA69 /* InfoPlist.strings */; };
967894941788ECDB00D6CA69 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 967894911788ECDB00D6CA69 /* MainMenu.xib */; };
967894961788ED1100D6CA69 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 967894951788ED1100D6CA69 /* main.m */; };
@ -35,6 +36,8 @@
96355CE51788E72A0010DBFA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
96355CE61788E72A0010DBFA /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
96355CE71788E72A0010DBFA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
9646869617BBC14E00C5EA69 /* platform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = platform.m; path = OSX/platform.m; sourceTree = SOURCE_ROOT; };
9646869717BBC14E00C5EA69 /* platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = platform.h; path = OSX/platform.h; sourceTree = SOURCE_ROOT; };
9678948D1788ECCA00D6CA69 /* RetroArch-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "RetroArch-Info.plist"; path = "OSX/RetroArch-Info.plist"; sourceTree = SOURCE_ROOT; };
967894901788ECDB00D6CA69 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = OSX/en.lproj/InfoPlist.strings; sourceTree = SOURCE_ROOT; };
967894921788ECDB00D6CA69 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = OSX/en.lproj/MainMenu.xib; sourceTree = SOURCE_ROOT; };
@ -109,6 +112,8 @@
96355CE81788E72A0010DBFA /* RetroArch */ = {
isa = PBXGroup;
children = (
9646869617BBC14E00C5EA69 /* platform.m */,
9646869717BBC14E00C5EA69 /* platform.h */,
9620F662178FD4D3001B3B81 /* settings.m */,
967894A01788F07D00D6CA69 /* griffin.c */,
967894971788F02600D6CA69 /* RAGameView.m */,
@ -214,6 +219,7 @@
9678949F1788F02600D6CA69 /* utility.m in Sources */,
967894A11788F07D00D6CA69 /* griffin.c in Sources */,
9620F663178FD4D3001B3B81 /* settings.m in Sources */,
9646869817BBC14E00C5EA69 /* platform.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -16,6 +16,7 @@
96366C5516C9AC3300D64A22 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96366C5416C9AC3300D64A22 /* CoreAudio.framework */; };
96366C5916C9ACF500D64A22 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96366C5816C9ACF500D64A22 /* AudioToolbox.framework */; };
963F5AC816CC523B009BBD19 /* RAGameView.m in Sources */ = {isa = PBXBuildFile; fileRef = 963F5AC516CC523B009BBD19 /* RAGameView.m */; };
9646869517BBBEAE00C5EA69 /* platform.m in Sources */ = {isa = PBXBuildFile; fileRef = 9646869417BBBEAE00C5EA69 /* platform.m */; };
966B9CBD16E41E7A005B61E1 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 966B9CB816E41E7A005B61E1 /* Default-568h@2x.png */; };
966B9CBF16E41E7A005B61E1 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 966B9CB916E41E7A005B61E1 /* Default.png */; };
966B9CC116E41E7A005B61E1 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 966B9CBA16E41E7A005B61E1 /* Default@2x.png */; };
@ -49,6 +50,7 @@
96366C5416C9AC3300D64A22 /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; };
96366C5816C9ACF500D64A22 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
963F5AC516CC523B009BBD19 /* RAGameView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RAGameView.m; sourceTree = "<group>"; };
9646869417BBBEAE00C5EA69 /* platform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = platform.m; path = iOS/platform.m; sourceTree = SOURCE_ROOT; };
966B9CB816E41E7A005B61E1 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = "<group>"; };
966B9CB916E41E7A005B61E1 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = "<group>"; };
966B9CBA16E41E7A005B61E1 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = "<group>"; };
@ -152,6 +154,7 @@
96AFAE3316C1D4EA009DE44C /* RetroArch */ = {
isa = PBXGroup;
children = (
9646869417BBBEAE00C5EA69 /* platform.m */,
967894571788EAAE00D6CA69 /* browser.m */,
967894581788EAAE00D6CA69 /* RALogView.m */,
967894591788EAAE00D6CA69 /* settings.m */,
@ -305,6 +308,7 @@
9678945B1788EAAE00D6CA69 /* browser.m in Sources */,
9678945C1788EAAE00D6CA69 /* RALogView.m in Sources */,
9678945D1788EAAE00D6CA69 /* settings.m in Sources */,
9646869517BBBEAE00C5EA69 /* platform.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

42
apple/iOS/platform.h Normal file
View File

@ -0,0 +1,42 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2013 - Jason Fetters
* Copyright (C) 2011-2013 - Daniel De Matteis
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __RARCH_IOS_PLATFORM_H
#define __RARCH_IOS_PLATFORM_H
@interface RAGameView : UIViewController
+ (RAGameView*)get;
- (void)openPauseMenu;
- (void)closePauseMenu;
@end
@interface RetroArch_iOS : UINavigationController<UIApplicationDelegate, UINavigationControllerDelegate, RetroArch_Platform>
+ (RetroArch_iOS*)get;
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file;
- (void)unloadingCore:(RAModuleInfo*)core;
- (NSString*)retroarchConfigPath;
- (void)refreshSystemConfig;
@property (strong, nonatomic) NSString* documentsDirectory; // e.g. /var/mobile/Documents
@property (strong, nonatomic) NSString* systemDirectory; // e.g. /var/mobile/Documents/.RetroArch
@property (strong, nonatomic) NSString* systemConfigPath; // e.g. /var/mobile/Documents/.RetroArch/frontend.cfg
@end
#endif

346
apple/iOS/platform.m Normal file
View File

@ -0,0 +1,346 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2013 - Jason Fetters
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <pthread.h>
#include <string.h>
#import "RetroArch_Apple.h"
#include "rarch_wrapper.h"
#include "../RetroArch/apple_input.h"
#import "views.h"
#include "input/BTStack/btpad.h"
#include "input/BTStack/btdynamic.h"
#include "input/BTStack/btpad.h"
#include "file.h"
//#define HAVE_DEBUG_FILELOG
// Input helpers: This is kept here because it needs objective-c
static void handle_touch_event(NSArray* touches)
{
const int numTouches = [touches count];
const float scale = [[UIScreen mainScreen] scale];
g_current_input_data.touch_count = 0;
for(int i = 0; i != numTouches && g_current_input_data.touch_count < MAX_TOUCHES; i ++)
{
UITouch* touch = [touches objectAtIndex:i];
const CGPoint coord = [touch locationInView:touch.view];
if (touch.phase != UITouchPhaseEnded && touch.phase != UITouchPhaseCancelled)
{
g_current_input_data.touches[g_current_input_data.touch_count ].screen_x = coord.x * scale;
g_current_input_data.touches[g_current_input_data.touch_count ++].screen_y = coord.y * scale;
}
}
}
@interface RApplication : UIApplication
@end
@implementation RApplication
- (void)sendEvent:(UIEvent *)event
{
[super sendEvent:event];
if ([[event allTouches] count])
handle_touch_event(event.allTouches.allObjects);
else if ([event respondsToSelector:@selector(_gsEvent)])
{
// Stolen from: http://nacho4d-nacho4d.blogspot.com/2012/01/catching-keyboard-events-in-ios.html
uint8_t* eventMem = (uint8_t*)(void*)CFBridgingRetain([event performSelector:@selector(_gsEvent)]);
int eventType = eventMem ? *(int*)&eventMem[8] : 0;
if (eventType == GSEVENT_TYPE_KEYDOWN || eventType == GSEVENT_TYPE_KEYUP)
apple_input_handle_key_event(*(uint16_t*)&eventMem[0x3C], eventType == GSEVENT_TYPE_KEYDOWN);
CFBridgingRelease(eventMem);
}
}
@end
@implementation RetroArch_iOS
{
UIWindow* _window;
bool _isGameTop, _isRomList;
uint32_t _settingMenusInBackStack;
uint32_t _enabledOrientations;
RAModuleInfo* _module;
}
+ (RetroArch_iOS*)get
{
return (RetroArch_iOS*)[[UIApplication sharedApplication] delegate];
}
#pragma mark LIFECYCLE (UIApplicationDelegate)
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
apple_platform = self;
self.delegate = self;
// Setup window
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
_window.rootViewController = self;
[_window makeKeyAndVisible];
// Build system paths and test permissions
self.documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
self.systemDirectory = [self.documentsDirectory stringByAppendingPathComponent:@".RetroArch"];
self.systemConfigPath = [self.systemDirectory stringByAppendingPathComponent:@"frontend.cfg"];
if (!path_make_and_check_directory(self.documentsDirectory.UTF8String, 0755, R_OK | W_OK | X_OK))
apple_display_alert([NSString stringWithFormat:@"Failed to create or access base directory: %@", self.documentsDirectory], 0);
else if (!path_make_and_check_directory(self.systemDirectory.UTF8String, 0755, R_OK | W_OK | X_OK))
apple_display_alert([NSString stringWithFormat:@"Failed to create or access system directory: %@", self.systemDirectory], 0);
else
{
[self pushViewController:[RADirectoryList directoryListAtBrowseRoot] animated:YES];
[self refreshSystemConfig];
if (apple_use_tv_mode)
apple_run_core(nil, 0);
}
// Warn if there are no cores present
if ([RAModuleInfo getModules].count == 0)
apple_display_alert(@"No libretro cores were found. You will not be able to play any games.", 0);
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
apple_enter_stasis();
}
- (void)applicationWillResignActive:(UIApplication *)application
{
apple_exit_stasis();
}
// UINavigationControllerDelegate
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
_isGameTop = [viewController isKindOfClass:[RAGameView class]];
_isRomList = [viewController isKindOfClass:[RADirectoryList class]];
[[UIApplication sharedApplication] setStatusBarHidden:_isGameTop withAnimation:UIStatusBarAnimationNone];
[[UIApplication sharedApplication] setIdleTimerDisabled:_isGameTop];
self.navigationBarHidden = _isGameTop;
[self setToolbarHidden:!_isRomList animated:YES];
self.topViewController.navigationItem.rightBarButtonItem = [self createSettingsButton];
}
// UINavigationController: Never animate when pushing onto, or popping, an RAGameView
- (void)pushViewController:(UIViewController*)theView animated:(BOOL)animated
{
if ([theView respondsToSelector:@selector(isSettingsView)] && [(id)theView isSettingsView])
_settingMenusInBackStack ++;
[super pushViewController:theView animated:animated && !_isGameTop];
}
- (UIViewController*)popViewControllerAnimated:(BOOL)animated
{
if ([self.topViewController respondsToSelector:@selector(isSettingsView)] && [(id)self.topViewController isSettingsView])
_settingMenusInBackStack --;
return [super popViewControllerAnimated:animated && !_isGameTop];
}
// NOTE: This version only runs on iOS6
- (NSUInteger)supportedInterfaceOrientations
{
return _isGameTop ? _enabledOrientations
: UIInterfaceOrientationMaskAll;
}
// NOTE: This version runs on iOS2-iOS5, but not iOS6
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (_isGameTop)
switch (interfaceOrientation)
{
case UIInterfaceOrientationPortrait:
return (_enabledOrientations & UIInterfaceOrientationMaskPortrait);
case UIInterfaceOrientationPortraitUpsideDown:
return (_enabledOrientations & UIInterfaceOrientationMaskPortraitUpsideDown);
case UIInterfaceOrientationLandscapeLeft:
return (_enabledOrientations & UIInterfaceOrientationMaskLandscapeLeft);
case UIInterfaceOrientationLandscapeRight:
return (_enabledOrientations & UIInterfaceOrientationMaskLandscapeRight);
}
return YES;
}
#pragma mark RetroArch_Platform
- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file
{
[self pushViewController:RAGameView.get animated:NO];
[RASettingsList refreshModuleConfig:core];
btpad_set_inquiry_state(false);
[self refreshSystemConfig];
}
- (void)unloadingCore:(RAModuleInfo*)core
{
[self popToViewController:[RAGameView get] animated:NO];
[self popViewControllerAnimated:NO];
btpad_set_inquiry_state(true);
}
- (NSString*)retroarchConfigPath
{
return [NSString stringWithFormat:@"%@/retroarch.cfg", self.systemDirectory];
}
- (NSString*)corePath
{
return [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"modules"];
}
#pragma mark FRONTEND CONFIG
- (void)refreshSystemConfig
{
// Read load time settings
config_file_t* conf = config_file_new([self.systemConfigPath UTF8String]);
if (conf)
{
// Get enabled orientations
static const struct { const char* setting; uint32_t orientation; } orientationSettings[4] =
{
{ "ios_allow_portrait", UIInterfaceOrientationMaskPortrait },
{ "ios_allow_portrait_upside_down", UIInterfaceOrientationMaskPortraitUpsideDown },
{ "ios_allow_landscape_left", UIInterfaceOrientationMaskLandscapeLeft },
{ "ios_allow_landscape_right", UIInterfaceOrientationMaskLandscapeRight }
};
_enabledOrientations = 0;
for (int i = 0; i < 4; i ++)
{
bool enabled = false;
bool found = config_get_bool(conf, orientationSettings[i].setting, &enabled);
if (!found || enabled)
_enabledOrientations |= orientationSettings[i].orientation;
}
// Setup bluetooth mode
NSString* btmode = objc_get_value_from_config(conf, @"ios_btmode", @"keyboard");
apple_input_enable_icade([btmode isEqualToString:@"icade"]);
btstack_set_poweron([btmode isEqualToString:@"btstack"]);
bool val;
apple_use_tv_mode = config_get_bool(conf, "ios_tv_mode", & val) && val;
config_file_free(conf);
}
}
#pragma mark PAUSE MENU
- (UIBarButtonItem*)createSettingsButton
{
if (_settingMenusInBackStack == 0)
return [[UIBarButtonItem alloc]
initWithTitle:@"Settings"
style:UIBarButtonItemStyleBordered
target:[RetroArch_iOS get]
action:@selector(showSystemSettings)];
else
return nil;
}
- (IBAction)showPauseMenu:(id)sender
{
if (apple_is_running && !apple_is_paused && _isGameTop)
{
apple_is_paused = true;
[[RAGameView get] openPauseMenu];
btpad_set_inquiry_state(true);
}
}
- (IBAction)basicEvent:(id)sender
{
if (apple_is_running)
apple_frontend_post_event(&apple_event_basic_command, ((UIView*)sender).tag);
[self closePauseMenu:sender];
}
- (IBAction)chooseState:(id)sender
{
if (apple_is_running)
apple_frontend_post_event(apple_event_set_state_slot, (void*)((UISegmentedControl*)sender).selectedSegmentIndex);
}
- (IBAction)showRGUI:(id)sender
{
if (apple_is_running)
apple_frontend_post_event(apple_event_show_rgui, 0);
[self closePauseMenu:sender];
}
- (IBAction)closePauseMenu:(id)sender
{
[[RAGameView get] closePauseMenu];
apple_is_paused = false;
btpad_set_inquiry_state(false);
}
- (IBAction)showSettings
{
[self pushViewController:[[RASettingsList alloc] initWithModule:_module] animated:YES];
}
- (IBAction)showSystemSettings
{
[self pushViewController:[RASystemSettingsList new] animated:YES];
}
@end
int main(int argc, char *argv[])
{
@autoreleasepool {
#if defined(HAVE_DEBUG_FILELOG) && (TARGET_IPHONE_SIMULATOR == 0)
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *logPath = [documentsDirectory stringByAppendingPathComponent:@"console_stdout.log"];
freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding], "a", stdout);
freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding], "a", stderr);
#endif
return UIApplicationMain(argc, argv, NSStringFromClass([RApplication class]), NSStringFromClass([RetroArch_iOS class]));
}
}

View File

@ -345,7 +345,7 @@ static NSArray* build_input_port_group(config_file_t* config, uint32_t player)
config_file_free(config);
}
[[RetroArch_iOS get] refreshConfig];
apple_refresh_config();
}
}