From 8ae3fcb6c1f8cf52a3b2eec6775efb77c920ee16 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 4 Apr 2013 07:54:33 +0200 Subject: [PATCH] (iOS) Reduce the amount of object files for Obj-C compiled code by combining similar files --- ios/RetroArch.xcodeproj/project.pbxproj | 16 -- ios/RetroArch/RAModuleInfo.m | 57 ++++ ios/RetroArch/RAModuleInfoList.m | 72 ------ ios/RetroArch/RetroArch_iOS.m | 328 ------------------------ ios/RetroArch/browser/RADirectoryGrid.m | 119 --------- ios/RetroArch/browser/RADirectoryList.m | 77 ------ ios/RetroArch/browser/browser.m | 164 ++++++++++++ ios/RetroArch/main.m | 313 ++++++++++++++++++++++ 8 files changed, 534 insertions(+), 612 deletions(-) delete mode 100644 ios/RetroArch/RAModuleInfoList.m delete mode 100644 ios/RetroArch/RetroArch_iOS.m delete mode 100644 ios/RetroArch/browser/RADirectoryGrid.m delete mode 100644 ios/RetroArch/browser/RADirectoryList.m diff --git a/ios/RetroArch.xcodeproj/project.pbxproj b/ios/RetroArch.xcodeproj/project.pbxproj index cc4b0e6e58..86855f92dc 100644 --- a/ios/RetroArch.xcodeproj/project.pbxproj +++ b/ios/RetroArch.xcodeproj/project.pbxproj @@ -8,10 +8,8 @@ /* Begin PBXBuildFile section */ 9605EA9B170288EA001D47B0 /* RAModuleInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 9605EA9A170288EA001D47B0 /* RAModuleInfo.m */; }; - 96096DD816D1ABAF00BF4499 /* RAModuleInfoList.m in Sources */ = {isa = PBXBuildFile; fileRef = 96096DD716D1ABAF00BF4499 /* RAModuleInfoList.m */; }; 962979F616C43B9500E6DCE0 /* ic_dir.png in Resources */ = {isa = PBXBuildFile; fileRef = 962979F416C43B9500E6DCE0 /* ic_dir.png */; }; 962979F716C43B9500E6DCE0 /* ic_file.png in Resources */ = {isa = PBXBuildFile; fileRef = 962979F516C43B9500E6DCE0 /* ic_file.png */; }; - 96297A0C16C5AD8D00E6DCE0 /* RetroArch_iOS.m in Sources */ = {isa = PBXBuildFile; fileRef = 96297A0B16C5AD8D00E6DCE0 /* RetroArch_iOS.m */; }; 96297A0F16C5AEA100E6DCE0 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 96297A0E16C5AEA100E6DCE0 /* main.m */; }; 96297A2716C82FF100E6DCE0 /* overlays in Resources */ = {isa = PBXBuildFile; fileRef = 96297A2616C82FF100E6DCE0 /* overlays */; }; 96366C5516C9AC3300D64A22 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96366C5416C9AC3300D64A22 /* CoreAudio.framework */; }; @@ -22,8 +20,6 @@ 963F5AC316CC522F009BBD19 /* RASettingsList.m in Sources */ = {isa = PBXBuildFile; fileRef = 963F5ABF16CC522F009BBD19 /* RASettingsList.m */; }; 963F5AC816CC523B009BBD19 /* RAGameView.m in Sources */ = {isa = PBXBuildFile; fileRef = 963F5AC516CC523B009BBD19 /* RAGameView.m */; }; 966B9CAE16E41C07005B61E1 /* browser.m in Sources */ = {isa = PBXBuildFile; fileRef = 966B9CAA16E41C07005B61E1 /* browser.m */; }; - 966B9CB016E41C07005B61E1 /* RADirectoryGrid.m in Sources */ = {isa = PBXBuildFile; fileRef = 966B9CAB16E41C07005B61E1 /* RADirectoryGrid.m */; }; - 966B9CB216E41C07005B61E1 /* RADirectoryList.m in Sources */ = {isa = PBXBuildFile; fileRef = 966B9CAC16E41C07005B61E1 /* RADirectoryList.m */; }; 966B9CB416E41C07005B61E1 /* RAModuleList.m in Sources */ = {isa = PBXBuildFile; fileRef = 966B9CAD16E41C07005B61E1 /* RAModuleList.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 */; }; @@ -47,12 +43,10 @@ /* Begin PBXFileReference section */ 9605EA99170288EA001D47B0 /* RAModuleInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RAModuleInfo.h; sourceTree = ""; }; 9605EA9A170288EA001D47B0 /* RAModuleInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RAModuleInfo.m; sourceTree = ""; }; - 96096DD716D1ABAF00BF4499 /* RAModuleInfoList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RAModuleInfoList.m; sourceTree = ""; }; 9614C71F16DDC018000B36EF /* RetroArch copy-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "RetroArch copy-Info.plist"; path = "/Users/jason/Documents/Projects/ios/RetroArch/ios/RetroArch copy-Info.plist"; sourceTree = ""; }; 962979F416C43B9500E6DCE0 /* ic_dir.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ic_dir.png; path = "../../android/phoenix/res/drawable-xhdpi/ic_dir.png"; sourceTree = ""; }; 962979F516C43B9500E6DCE0 /* ic_file.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ic_file.png; path = "../../android/phoenix/res/drawable-xhdpi/ic_file.png"; sourceTree = ""; }; 96297A0A16C5AD8D00E6DCE0 /* RetroArch_iOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RetroArch_iOS.h; sourceTree = ""; }; - 96297A0B16C5AD8D00E6DCE0 /* RetroArch_iOS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RetroArch_iOS.m; sourceTree = ""; }; 96297A0D16C5ADDA00E6DCE0 /* views.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = views.h; sourceTree = ""; }; 96297A0E16C5AEA100E6DCE0 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 96297A2616C82FF100E6DCE0 /* overlays */ = {isa = PBXFileReference; lastKnownFileType = folder; name = overlays; path = ../../media/overlays; sourceTree = ""; }; @@ -66,8 +60,6 @@ 963F5AC516CC523B009BBD19 /* RAGameView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RAGameView.m; sourceTree = ""; }; 966B9CA916E41C07005B61E1 /* browser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = browser.h; sourceTree = ""; }; 966B9CAA16E41C07005B61E1 /* browser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = browser.m; sourceTree = ""; }; - 966B9CAB16E41C07005B61E1 /* RADirectoryGrid.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RADirectoryGrid.m; sourceTree = ""; }; - 966B9CAC16E41C07005B61E1 /* RADirectoryList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RADirectoryList.m; sourceTree = ""; }; 966B9CAD16E41C07005B61E1 /* RAModuleList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RAModuleList.m; sourceTree = ""; }; 966B9CB816E41E7A005B61E1 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 966B9CB916E41E7A005B61E1 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; @@ -131,8 +123,6 @@ children = ( 966B9CA916E41C07005B61E1 /* browser.h */, 966B9CAA16E41C07005B61E1 /* browser.m */, - 966B9CAB16E41C07005B61E1 /* RADirectoryGrid.m */, - 966B9CAC16E41C07005B61E1 /* RADirectoryList.m */, 966B9CAD16E41C07005B61E1 /* RAModuleList.m */, ); path = browser; @@ -201,10 +191,8 @@ 96F9C28216FFA55F002455B3 /* RALogView.m */, 9605EA9A170288EA001D47B0 /* RAModuleInfo.m */, 9605EA99170288EA001D47B0 /* RAModuleInfo.h */, - 96096DD716D1ABAF00BF4499 /* RAModuleInfoList.m */, 96C19C2616D455BE00FE8D5A /* rarch_wrapper.h */, 96297A0A16C5AD8D00E6DCE0 /* RetroArch_iOS.h */, - 96297A0B16C5AD8D00E6DCE0 /* RetroArch_iOS.m */, 96297A0D16C5ADDA00E6DCE0 /* views.h */, ); path = RetroArch; @@ -342,17 +330,13 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 96297A0C16C5AD8D00E6DCE0 /* RetroArch_iOS.m in Sources */, 96297A0F16C5AEA100E6DCE0 /* main.m in Sources */, 963F5AC016CC522F009BBD19 /* RAButtonGetter.m in Sources */, 963F5AC116CC522F009BBD19 /* RASettingEnumerationList.m in Sources */, 963F5AC216CC522F009BBD19 /* RASettingsSubList.m in Sources */, 963F5AC316CC522F009BBD19 /* RASettingsList.m in Sources */, 963F5AC816CC523B009BBD19 /* RAGameView.m in Sources */, - 96096DD816D1ABAF00BF4499 /* RAModuleInfoList.m in Sources */, 966B9CAE16E41C07005B61E1 /* browser.m in Sources */, - 966B9CB016E41C07005B61E1 /* RADirectoryGrid.m in Sources */, - 966B9CB216E41C07005B61E1 /* RADirectoryList.m in Sources */, 966B9CB416E41C07005B61E1 /* RAModuleList.m in Sources */, D48581DE16F823F9004BEB17 /* griffin.c in Sources */, 96F9C28316FFA55F002455B3 /* RALogView.m in Sources */, diff --git a/ios/RetroArch/RAModuleInfo.m b/ios/RetroArch/RAModuleInfo.m index 217f8eca68..02a40b2496 100644 --- a/ios/RetroArch/RAModuleInfo.m +++ b/ios/RetroArch/RAModuleInfo.m @@ -17,6 +17,10 @@ #import "RAModuleInfo.h" static NSMutableArray* moduleList; +static NSString* const labels[3] = {@"Core Name", @"Developer", @"Name"}; +static const char* const keys[3] = {"corename", "manufacturer", "systemname"}; +static NSString* const sectionNames[2] = {@"Emulator", @"Hardware"}; +static const uint32_t sectionSizes[2] = {1, 2}; @implementation RAModuleInfo + (NSArray*)getModules @@ -81,3 +85,56 @@ static NSMutableArray* moduleList; } @end + +@implementation RAModuleInfoList +{ + RAModuleInfo* _data; +} + +- (id)initWithModuleInfo:(RAModuleInfo*)info +{ + self = [super initWithStyle:UITableViewStyleGrouped]; + + _data = info; + return self; +} + +- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView +{ + return sizeof(sectionSizes) / sizeof(sectionSizes[0]); +} + +- (NSString*)tableView:(UITableView*)tableView titleForHeaderInSection:(NSInteger)section +{ + return sectionNames[section]; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return sectionSizes[section]; +} + +- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:@"datacell"]; + cell = (cell != nil) ? cell : [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"datacell"]; + + uint32_t sectionBase = 0; + for (int i = 0; i != indexPath.section; i ++) + { + sectionBase += sectionSizes[i]; + } + + cell.textLabel.text = labels[sectionBase + indexPath.row]; + + char* val = 0; + if (_data.data) + config_get_string(_data.data, keys[sectionBase + indexPath.row], &val); + + cell.detailTextLabel.text = val ? [NSString stringWithUTF8String:val] : @"Unspecified"; + free(val); + + return cell; +} + +@end diff --git a/ios/RetroArch/RAModuleInfoList.m b/ios/RetroArch/RAModuleInfoList.m deleted file mode 100644 index 64311028e4..0000000000 --- a/ios/RetroArch/RAModuleInfoList.m +++ /dev/null @@ -1,72 +0,0 @@ -/* 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 . - */ - -static NSString* const labels[3] = {@"Core Name", @"Developer", @"Name"}; -static const char* const keys[3] = {"corename", "manufacturer", "systemname"}; -static NSString* const sectionNames[2] = {@"Emulator", @"Hardware"}; -static const uint32_t sectionSizes[2] = {1, 2}; - -@implementation RAModuleInfoList -{ - RAModuleInfo* _data; -} - -- (id)initWithModuleInfo:(RAModuleInfo*)info -{ - self = [super initWithStyle:UITableViewStyleGrouped]; - - _data = info; - return self; -} - -- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView -{ - return sizeof(sectionSizes) / sizeof(sectionSizes[0]); -} - -- (NSString*)tableView:(UITableView*)tableView titleForHeaderInSection:(NSInteger)section -{ - return sectionNames[section]; -} - -- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section -{ - return sectionSizes[section]; -} - -- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath -{ - UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:@"datacell"]; - cell = (cell != nil) ? cell : [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"datacell"]; - - uint32_t sectionBase = 0; - for (int i = 0; i != indexPath.section; i ++) - { - sectionBase += sectionSizes[i]; - } - - cell.textLabel.text = labels[sectionBase + indexPath.row]; - - char* val = 0; - if (_data.data) - config_get_string(_data.data, keys[sectionBase + indexPath.row], &val); - - cell.detailTextLabel.text = val ? [NSString stringWithUTF8String:val] : @"Unspecified"; - free(val); - - return cell; -} - -@end diff --git a/ios/RetroArch/RetroArch_iOS.m b/ios/RetroArch/RetroArch_iOS.m deleted file mode 100644 index 3ef7573210..0000000000 --- a/ios/RetroArch/RetroArch_iOS.m +++ /dev/null @@ -1,328 +0,0 @@ -/* 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 . - */ - -#include -#include - -#include "rarch_wrapper.h" -#include "general.h" -#include "frontend/menu/rmenu.h" - -#import "browser/browser.h" -#import "settings/settings.h" - -#include "input/BTStack/btdynamic.h" -#include "input/BTStack/btpad.h" - -#define kDOCSFOLDER [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] - -// From frontend/frontend_ios.c -extern void* rarch_main_ios(void* args); -extern void ios_frontend_post_event(void (*fn)(void*), void* userdata); - -static void event_game_reset(void* userdata) -{ - rarch_game_reset(); -} - -static void event_load_state(void* userdata) -{ - rarch_load_state(); -} - -static void event_save_state(void* userdata) -{ - rarch_save_state(); -} - -static void event_set_state_slot(void* userdata) -{ - g_extern.state_slot = (uint32_t)userdata; -} - -static void event_quit(void* userdata) -{ - g_extern.system.shutdown = true; -} - -static void event_reload_config(void* userdata) -{ - // Need to clear these otherwise stale versions may be used! - memset(g_settings.input.overlay, 0, sizeof(g_settings.input.overlay)); - memset(g_settings.video.xml_shader_path, 0, sizeof(g_settings.video.xml_shader_path)); - - uninit_drivers(); - config_load(); - init_drivers(); -} - -@implementation RetroArch_iOS -{ - UIWindow* _window; - - pthread_t _retroThread; - - bool _isGameTop; - bool _isPaused; - bool _isRunning; -} - -+ (void)displayErrorMessage:(NSString*)message -{ - UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"RetroArch" - message:message - delegate:nil - cancelButtonTitle:@"OK" - otherButtonTitles:nil]; - [alert show]; -} - -+ (RetroArch_iOS*)get -{ - return (RetroArch_iOS*)[[UIApplication sharedApplication] delegate]; -} - -// UIApplicationDelegate -- (void)applicationDidFinishLaunching:(UIApplication *)application -{ - self.system_directory = [NSString stringWithFormat:@"%@/.RetroArch", kDOCSFOLDER]; - mkdir([self.system_directory UTF8String], 0755); - - // Setup window - self.delegate = self; - [self pushViewController:[RADirectoryList directoryListOrGridWithPath:kDOCSFOLDER] animated:YES]; - - _window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; - _window.rootViewController = self; - [_window makeKeyAndVisible]; -} - -- (void)applicationWillEnterForeground:(UIApplication *)application -{ - [RAGameView.get resume]; -} - -- (void)applicationDidEnterBackground:(UIApplication *)application -{ - [RAGameView.get suspend]; -} - -// UINavigationControllerDelegate -- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated -{ - _isGameTop = [viewController isKindOfClass:[RAGameView class]]; - [[UIApplication sharedApplication] setStatusBarHidden:_isGameTop withAnimation:UIStatusBarAnimationNone]; - self.navigationBarHidden = _isGameTop; - - self.topViewController.navigationItem.rightBarButtonItem = [self createBluetoothButton]; -} - -// UINavigationController: Never animate when pushing onto, or popping, an RAGameView -- (void)pushViewController:(UIViewController*)theView animated:(BOOL)animated -{ - [super pushViewController:theView animated:animated && !_isGameTop]; -} - -- (UIViewController*)popViewControllerAnimated:(BOOL)animated -{ - return [super popViewControllerAnimated:animated && !_isGameTop]; -} - -#pragma mark EMULATION -- (void)runGame:(NSString*)path -{ - if (_isRunning) - return; - - assert(self.moduleInfo); - - [RASettingsList refreshConfigFile]; - - [self pushViewController:RAGameView.get animated:NO]; - _isRunning = true; - - const char* const sd = [[RetroArch_iOS get].system_directory UTF8String]; - const char* const cf = (ra_ios_is_file(self.moduleInfo.configPath)) ? [self.moduleInfo.configPath UTF8String] : 0; - const char* const libretro = [self.moduleInfo.path UTF8String]; - - struct rarch_main_wrap* load_data = malloc(sizeof(struct rarch_main_wrap)); - load_data->libretro_path = strdup(libretro); - load_data->rom_path = strdup([path UTF8String]); - load_data->sram_path = strdup(sd); - load_data->state_path = strdup(sd); - load_data->verbose = false; - load_data->config_path = strdup(cf); - if (pthread_create(&_retroThread, 0, rarch_main_ios, load_data)) - { - [self rarchExited:NO]; - } - pthread_detach(_retroThread); - - // Read load time settings - // TODO: Do this better - config_file_t* conf = config_file_new([self.moduleInfo.configPath UTF8String]); - bool autoStartBluetooth = false; - if (conf && config_get_bool(conf, "ios_auto_bluetooth", &autoStartBluetooth) && autoStartBluetooth) - [self startBluetooth]; - config_file_free(conf); -} - -- (void)rarchExited:(BOOL)successful -{ - if (!successful) - { - [RetroArch_iOS displayErrorMessage:@"Failed to load game."]; - } - - if (_isRunning) - { - _isRunning = false; - - // Stop bluetooth (might be annoying but forgetting could eat battery of device AND wiimote) - [self stopBluetooth]; - - // - [self popToViewController:[RAGameView get] animated:NO]; - [self popViewControllerAnimated:NO]; - } -} - -- (void)refreshConfig -{ - if (_isRunning) - ios_frontend_post_event(&event_reload_config, 0); - else - { - // Need to clear these otherwise stale versions may be used! - memset(g_settings.input.overlay, 0, sizeof(g_settings.input.overlay)); - memset(g_settings.video.xml_shader_path, 0, sizeof(g_settings.video.xml_shader_path)); - } -} - -#pragma mark PAUSE MENU -- (IBAction)showPauseMenu:(id)sender -{ - if (_isRunning && !_isPaused && _isGameTop) - { - _isPaused = true; - [[RAGameView get] openPauseMenu]; - } -} - -- (IBAction)resetGame:(id)sender -{ - if (_isRunning) - ios_frontend_post_event(&event_game_reset, 0); - - [self closePauseMenu:sender]; -} - -- (IBAction)loadState:(id)sender -{ - if (_isRunning) - ios_frontend_post_event(&event_load_state, 0); - - [self closePauseMenu:sender]; -} - -- (IBAction)saveState:(id)sender -{ - if (_isRunning) - ios_frontend_post_event(&event_save_state, 0); - - [self closePauseMenu:sender]; -} - -- (IBAction)chooseState:(id)sender -{ - if (_isRunning) - ios_frontend_post_event(event_set_state_slot, (void*)((UISegmentedControl*)sender).selectedSegmentIndex); -} - -- (IBAction)closePauseMenu:(id)sender -{ - [[RAGameView get] closePauseMenu]; - _isPaused = false; -} - -- (IBAction)closeGamePressed:(id)sender -{ - [self closePauseMenu:sender]; - ios_frontend_post_event(event_quit, 0); -} - -- (IBAction)showSettings -{ - [self pushViewController:[RASettingsList new] animated:YES]; -} - -#pragma mark Bluetooth Helpers -- (UIBarButtonItem*)createBluetoothButton -{ - if (btstack_is_loaded()) - { - const bool isBTOn = btstack_is_running(); - return [[UIBarButtonItem alloc] - initWithTitle:isBTOn ? @"Stop Bluetooth" : @"Start Bluetooth" - style:UIBarButtonItemStyleBordered - target:[RetroArch_iOS get] - action:isBTOn ? @selector(stopBluetooth) : @selector(startBluetooth)]; - } - else - return nil; -} - -- (IBAction)startBluetooth -{ - if (btstack_is_loaded() && !btstack_is_running()) - { - UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"RetroArch" - message:@"Choose Pad Type" - delegate:self - cancelButtonTitle:@"Cancel" - otherButtonTitles:@"Wii", @"PS3", nil]; - [alert show]; - } -} - -- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex -{ - if (btstack_is_loaded()) - { - btpad_set_pad_type(buttonIndex == alertView.firstOtherButtonIndex); - - if (buttonIndex != alertView.cancelButtonIndex) - { - btstack_start(); - [self.topViewController.navigationItem setRightBarButtonItem:[self createBluetoothButton] animated:YES]; - } - } -} - -- (IBAction)stopBluetooth -{ - if (btstack_is_loaded()) - { - btstack_stop(); - [self.topViewController.navigationItem setRightBarButtonItem:[self createBluetoothButton] animated:YES]; - } -} - -@end - -void ios_rarch_exited(void* result) -{ - [[RetroArch_iOS get] rarchExited:result ? NO : YES]; -} diff --git a/ios/RetroArch/browser/RADirectoryGrid.m b/ios/RetroArch/browser/RADirectoryGrid.m deleted file mode 100644 index d0f7eab792..0000000000 --- a/ios/RetroArch/browser/RADirectoryGrid.m +++ /dev/null @@ -1,119 +0,0 @@ -/* 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 . - */ - -#import "conf/config_file.h" -#import "browser.h" - -@implementation RADirectoryGrid -{ - NSString* _path; - NSArray* _list; -} - -- (id)initWithPath:(NSString*)path -{ - _path = path; - _list = ra_ios_list_directory(_path); - - [self setTitle: [_path lastPathComponent]]; - - unsigned tileWidth = 100; - unsigned tileHeight = 100; - - config_file_t* config = config_file_new([[path stringByAppendingPathComponent:@".raconfig"] UTF8String]); - if (config) - { - config_get_uint(config, "cover_width", &tileWidth); - config_get_uint(config, "cover_height", &tileHeight); - config_file_free(config); - } - - // Init collection view - UICollectionViewFlowLayout* layout = [UICollectionViewFlowLayout new]; - layout.itemSize = CGSizeMake(tileWidth, tileHeight); - self = [super initWithCollectionViewLayout:layout]; - - [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"dircell"]; - [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"textcell"]; - [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"imagecell"]; - - return self; -} - -- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView -{ - return 1; -} - -- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section -{ - return [_list count]; -} - -- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath -{ - RADirectoryItem* path = [_list objectAtIndex: indexPath.row]; - - if(path.isDirectory) - [[RetroArch_iOS get] pushViewController:[RADirectoryList directoryListOrGridWithPath:path.path] animated:YES]; - else - [[RetroArch_iOS get] pushViewController:[[RAModuleList alloc] initWithGame:path.path] animated:YES]; -} - -- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath -{ - RADirectoryItem* path = [_list objectAtIndex: indexPath.row]; - UICollectionViewCell* cell = nil; - - if (path.isDirectory) - { - cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:@"dircell" forIndexPath:indexPath]; - - if (!cell.backgroundView) - { - cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"ic_dir"]]; - ((UIImageView*)cell.backgroundView).contentMode = UIViewContentModeScaleAspectFit; - } - } - else if (path.coverPath) - { - cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:@"imagecell" forIndexPath:indexPath]; - - if (!cell.backgroundView) - { - cell.backgroundView = [UIImageView new]; - ((UIImageView*)cell.backgroundView).contentMode = UIViewContentModeScaleAspectFit; - } - - ((UIImageView*)cell.backgroundView).image = [UIImage imageWithContentsOfFile:path.coverPath]; - } - else - { - cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:@"textcell" forIndexPath:indexPath]; - - if (!cell.backgroundView) - { - cell.backgroundView = [UILabel new]; - ((UILabel*)cell.backgroundView).numberOfLines = 0; - ((UILabel*)cell.backgroundView).textAlignment = NSTextAlignmentCenter; - } - - ((UILabel*)cell.backgroundView).text = [path.path lastPathComponent]; - } - - return cell; -} - -@end diff --git a/ios/RetroArch/browser/RADirectoryList.m b/ios/RetroArch/browser/RADirectoryList.m deleted file mode 100644 index 2c7d6314d1..0000000000 --- a/ios/RetroArch/browser/RADirectoryList.m +++ /dev/null @@ -1,77 +0,0 @@ -/* 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 . - */ - -#import "browser.h" - -@implementation RADirectoryList -{ - NSString* _path; - NSArray* _list; -} - -+ (id)directoryListOrGridWithPath:(NSString*)path -{ - path = ra_ios_check_path(path); - - if ([UICollectionViewController instancesRespondToSelector:@selector(initWithCollectionViewLayout:)]) - { - NSString* coverDir = [path stringByAppendingPathComponent:@".coverart"]; - if (ra_ios_is_directory(coverDir)) - return [[RADirectoryGrid alloc] initWithPath:path]; - } - - return [[RADirectoryList alloc] initWithPath:path]; -} - -- (id)initWithPath:(NSString*)path -{ - self = [super initWithStyle:UITableViewStylePlain]; - - _path = path; - _list = ra_ios_list_directory(_path); - - [self setTitle: [_path lastPathComponent]]; - - return self; -} - -- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath -{ - RADirectoryItem* path = [_list objectAtIndex: indexPath.row]; - - if(path.isDirectory) - [[RetroArch_iOS get] pushViewController:[RADirectoryList directoryListOrGridWithPath:path.path] animated:YES]; - else - [[RetroArch_iOS get] pushViewController:[[RAModuleList alloc] initWithGame:path.path] animated:YES]; -} - -- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section -{ - return [_list count]; -} - -- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath -{ - RADirectoryItem* path = [_list objectAtIndex: indexPath.row]; - - UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:@"path"]; - cell = (cell != nil) ? cell : [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"path"]; - cell.textLabel.text = [path.path lastPathComponent]; - cell.accessoryType = (path.isDirectory) ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone; - cell.imageView.image = [UIImage imageNamed:(path.isDirectory) ? @"ic_dir" : @"ic_file"]; - return cell; -} - -@end diff --git a/ios/RetroArch/browser/browser.m b/ios/RetroArch/browser/browser.m index 488103eb04..c70e4f4c32 100644 --- a/ios/RetroArch/browser/browser.m +++ b/ios/RetroArch/browser/browser.m @@ -16,6 +16,7 @@ #include #include #import "browser.h" +#import "conf/config_file.h" @implementation RADirectoryItem + (RADirectoryItem*)directoryItemFromPath:(const char*)thePath checkForCovers:(BOOL)checkCovers @@ -100,3 +101,166 @@ NSString* ra_ios_check_path(NSString* path) return [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]; } + +@implementation RADirectoryList +{ + NSString* _path; + NSArray* _list; +} + ++ (id)directoryListOrGridWithPath:(NSString*)path +{ + path = ra_ios_check_path(path); + + if ([UICollectionViewController instancesRespondToSelector:@selector(initWithCollectionViewLayout:)]) + { + NSString* coverDir = [path stringByAppendingPathComponent:@".coverart"]; + if (ra_ios_is_directory(coverDir)) + return [[RADirectoryGrid alloc] initWithPath:path]; + } + + return [[RADirectoryList alloc] initWithPath:path]; +} + +- (id)initWithPath:(NSString*)path +{ + self = [super initWithStyle:UITableViewStylePlain]; + + _path = path; + _list = ra_ios_list_directory(_path); + + [self setTitle: [_path lastPathComponent]]; + + return self; +} + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + RADirectoryItem* path = [_list objectAtIndex: indexPath.row]; + + if(path.isDirectory) + [[RetroArch_iOS get] pushViewController:[RADirectoryList directoryListOrGridWithPath:path.path] animated:YES]; + else + [[RetroArch_iOS get] pushViewController:[[RAModuleList alloc] initWithGame:path.path] animated:YES]; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return [_list count]; +} + +- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + RADirectoryItem* path = [_list objectAtIndex: indexPath.row]; + + UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:@"path"]; + cell = (cell != nil) ? cell : [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"path"]; + cell.textLabel.text = [path.path lastPathComponent]; + cell.accessoryType = (path.isDirectory) ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone; + cell.imageView.image = [UIImage imageNamed:(path.isDirectory) ? @"ic_dir" : @"ic_file"]; + return cell; +} + +@end + +@implementation RADirectoryGrid +{ + NSString* _path; + NSArray* _list; +} + +- (id)initWithPath:(NSString*)path +{ + _path = path; + _list = ra_ios_list_directory(_path); + + [self setTitle: [_path lastPathComponent]]; + + unsigned tileWidth = 100; + unsigned tileHeight = 100; + + config_file_t* config = config_file_new([[path stringByAppendingPathComponent:@".raconfig"] UTF8String]); + if (config) + { + config_get_uint(config, "cover_width", &tileWidth); + config_get_uint(config, "cover_height", &tileHeight); + config_file_free(config); + } + + // Init collection view + UICollectionViewFlowLayout* layout = [UICollectionViewFlowLayout new]; + layout.itemSize = CGSizeMake(tileWidth, tileHeight); + self = [super initWithCollectionViewLayout:layout]; + + [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"dircell"]; + [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"textcell"]; + [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"imagecell"]; + + return self; +} + +- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView +{ + return 1; +} + +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section +{ + return [_list count]; +} + +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath +{ + RADirectoryItem* path = [_list objectAtIndex: indexPath.row]; + + if(path.isDirectory) + [[RetroArch_iOS get] pushViewController:[RADirectoryList directoryListOrGridWithPath:path.path] animated:YES]; + else + [[RetroArch_iOS get] pushViewController:[[RAModuleList alloc] initWithGame:path.path] animated:YES]; +} + +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath +{ + RADirectoryItem* path = [_list objectAtIndex: indexPath.row]; + UICollectionViewCell* cell = nil; + + if (path.isDirectory) + { + cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:@"dircell" forIndexPath:indexPath]; + + if (!cell.backgroundView) + { + cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"ic_dir"]]; + ((UIImageView*)cell.backgroundView).contentMode = UIViewContentModeScaleAspectFit; + } + } + else if (path.coverPath) + { + cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:@"imagecell" forIndexPath:indexPath]; + + if (!cell.backgroundView) + { + cell.backgroundView = [UIImageView new]; + ((UIImageView*)cell.backgroundView).contentMode = UIViewContentModeScaleAspectFit; + } + + ((UIImageView*)cell.backgroundView).image = [UIImage imageWithContentsOfFile:path.coverPath]; + } + else + { + cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:@"textcell" forIndexPath:indexPath]; + + if (!cell.backgroundView) + { + cell.backgroundView = [UILabel new]; + ((UILabel*)cell.backgroundView).numberOfLines = 0; + ((UILabel*)cell.backgroundView).textAlignment = NSTextAlignmentCenter; + } + + ((UILabel*)cell.backgroundView).text = [path.path lastPathComponent]; + } + + return cell; +} + +@end diff --git a/ios/RetroArch/main.m b/ios/RetroArch/main.m index e3835d6e51..15d534c87f 100644 --- a/ios/RetroArch/main.m +++ b/ios/RetroArch/main.m @@ -18,6 +18,19 @@ #include "input/keycode.h" #include "libretro.h" +#include +#include + +#include "rarch_wrapper.h" +#include "general.h" +#include "frontend/menu/rmenu.h" + +#import "browser/browser.h" +#import "settings/settings.h" + +#include "input/BTStack/btdynamic.h" +#include "input/BTStack/btpad.h" + #define GSEVENT_TYPE_KEYDOWN 10 #define GSEVENT_TYPE_KEYUP 11 #define GSEVENT_TYPE_MODS 12 @@ -144,3 +157,303 @@ int main(int argc, char *argv[]) } } +#define kDOCSFOLDER [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] + +// From frontend/frontend_ios.c +extern void* rarch_main_ios(void* args); +extern void ios_frontend_post_event(void (*fn)(void*), void* userdata); + +static void event_game_reset(void* userdata) +{ + rarch_game_reset(); +} + +static void event_load_state(void* userdata) +{ + rarch_load_state(); +} + +static void event_save_state(void* userdata) +{ + rarch_save_state(); +} + +static void event_set_state_slot(void* userdata) +{ + g_extern.state_slot = (uint32_t)userdata; +} + +static void event_quit(void* userdata) +{ + g_extern.system.shutdown = true; +} + +static void event_reload_config(void* userdata) +{ + // Need to clear these otherwise stale versions may be used! + memset(g_settings.input.overlay, 0, sizeof(g_settings.input.overlay)); + memset(g_settings.video.xml_shader_path, 0, sizeof(g_settings.video.xml_shader_path)); + + uninit_drivers(); + config_load(); + init_drivers(); +} + +@implementation RetroArch_iOS +{ + UIWindow* _window; + + pthread_t _retroThread; + + bool _isGameTop; + bool _isPaused; + bool _isRunning; +} + ++ (void)displayErrorMessage:(NSString*)message +{ + UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"RetroArch" + message:message + delegate:nil + cancelButtonTitle:@"OK" + otherButtonTitles:nil]; + [alert show]; +} + ++ (RetroArch_iOS*)get +{ + return (RetroArch_iOS*)[[UIApplication sharedApplication] delegate]; +} + +// UIApplicationDelegate +- (void)applicationDidFinishLaunching:(UIApplication *)application +{ + self.system_directory = [NSString stringWithFormat:@"%@/.RetroArch", kDOCSFOLDER]; + mkdir([self.system_directory UTF8String], 0755); + + // Setup window + self.delegate = self; + [self pushViewController:[RADirectoryList directoryListOrGridWithPath:kDOCSFOLDER] animated:YES]; + + _window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + _window.rootViewController = self; + [_window makeKeyAndVisible]; +} + +- (void)applicationWillEnterForeground:(UIApplication *)application +{ + [RAGameView.get resume]; +} + +- (void)applicationDidEnterBackground:(UIApplication *)application +{ + [RAGameView.get suspend]; +} + +// UINavigationControllerDelegate +- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated +{ + _isGameTop = [viewController isKindOfClass:[RAGameView class]]; + [[UIApplication sharedApplication] setStatusBarHidden:_isGameTop withAnimation:UIStatusBarAnimationNone]; + self.navigationBarHidden = _isGameTop; + + self.topViewController.navigationItem.rightBarButtonItem = [self createBluetoothButton]; +} + +// UINavigationController: Never animate when pushing onto, or popping, an RAGameView +- (void)pushViewController:(UIViewController*)theView animated:(BOOL)animated +{ + [super pushViewController:theView animated:animated && !_isGameTop]; +} + +- (UIViewController*)popViewControllerAnimated:(BOOL)animated +{ + return [super popViewControllerAnimated:animated && !_isGameTop]; +} + +#pragma mark EMULATION +- (void)runGame:(NSString*)path +{ + if (_isRunning) + return; + + assert(self.moduleInfo); + + [RASettingsList refreshConfigFile]; + + [self pushViewController:RAGameView.get animated:NO]; + _isRunning = true; + + const char* const sd = [[RetroArch_iOS get].system_directory UTF8String]; + const char* const cf = (ra_ios_is_file(self.moduleInfo.configPath)) ? [self.moduleInfo.configPath UTF8String] : 0; + const char* const libretro = [self.moduleInfo.path UTF8String]; + + struct rarch_main_wrap* load_data = malloc(sizeof(struct rarch_main_wrap)); + load_data->libretro_path = strdup(libretro); + load_data->rom_path = strdup([path UTF8String]); + load_data->sram_path = strdup(sd); + load_data->state_path = strdup(sd); + load_data->verbose = false; + load_data->config_path = strdup(cf); + if (pthread_create(&_retroThread, 0, rarch_main_ios, load_data)) + { + [self rarchExited:NO]; + } + pthread_detach(_retroThread); + + // Read load time settings + // TODO: Do this better + config_file_t* conf = config_file_new([self.moduleInfo.configPath UTF8String]); + bool autoStartBluetooth = false; + if (conf && config_get_bool(conf, "ios_auto_bluetooth", &autoStartBluetooth) && autoStartBluetooth) + [self startBluetooth]; + config_file_free(conf); +} + +- (void)rarchExited:(BOOL)successful +{ + if (!successful) + { + [RetroArch_iOS displayErrorMessage:@"Failed to load game."]; + } + + if (_isRunning) + { + _isRunning = false; + + // Stop bluetooth (might be annoying but forgetting could eat battery of device AND wiimote) + [self stopBluetooth]; + + // + [self popToViewController:[RAGameView get] animated:NO]; + [self popViewControllerAnimated:NO]; + } +} + +- (void)refreshConfig +{ + if (_isRunning) + ios_frontend_post_event(&event_reload_config, 0); + else + { + // Need to clear these otherwise stale versions may be used! + memset(g_settings.input.overlay, 0, sizeof(g_settings.input.overlay)); + memset(g_settings.video.xml_shader_path, 0, sizeof(g_settings.video.xml_shader_path)); + } +} + +#pragma mark PAUSE MENU +- (IBAction)showPauseMenu:(id)sender +{ + if (_isRunning && !_isPaused && _isGameTop) + { + _isPaused = true; + [[RAGameView get] openPauseMenu]; + } +} + +- (IBAction)resetGame:(id)sender +{ + if (_isRunning) + ios_frontend_post_event(&event_game_reset, 0); + + [self closePauseMenu:sender]; +} + +- (IBAction)loadState:(id)sender +{ + if (_isRunning) + ios_frontend_post_event(&event_load_state, 0); + + [self closePauseMenu:sender]; +} + +- (IBAction)saveState:(id)sender +{ + if (_isRunning) + ios_frontend_post_event(&event_save_state, 0); + + [self closePauseMenu:sender]; +} + +- (IBAction)chooseState:(id)sender +{ + if (_isRunning) + ios_frontend_post_event(event_set_state_slot, (void*)((UISegmentedControl*)sender).selectedSegmentIndex); +} + +- (IBAction)closePauseMenu:(id)sender +{ + [[RAGameView get] closePauseMenu]; + _isPaused = false; +} + +- (IBAction)closeGamePressed:(id)sender +{ + [self closePauseMenu:sender]; + ios_frontend_post_event(event_quit, 0); +} + +- (IBAction)showSettings +{ + [self pushViewController:[RASettingsList new] animated:YES]; +} + +#pragma mark Bluetooth Helpers +- (UIBarButtonItem*)createBluetoothButton +{ + if (btstack_is_loaded()) + { + const bool isBTOn = btstack_is_running(); + return [[UIBarButtonItem alloc] + initWithTitle:isBTOn ? @"Stop Bluetooth" : @"Start Bluetooth" + style:UIBarButtonItemStyleBordered + target:[RetroArch_iOS get] + action:isBTOn ? @selector(stopBluetooth) : @selector(startBluetooth)]; + } + else + return nil; +} + +- (IBAction)startBluetooth +{ + if (btstack_is_loaded() && !btstack_is_running()) + { + UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"RetroArch" + message:@"Choose Pad Type" + delegate:self + cancelButtonTitle:@"Cancel" + otherButtonTitles:@"Wii", @"PS3", nil]; + [alert show]; + } +} + +- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex +{ + if (btstack_is_loaded()) + { + btpad_set_pad_type(buttonIndex == alertView.firstOtherButtonIndex); + + if (buttonIndex != alertView.cancelButtonIndex) + { + btstack_start(); + [self.topViewController.navigationItem setRightBarButtonItem:[self createBluetoothButton] animated:YES]; + } + } +} + +- (IBAction)stopBluetooth +{ + if (btstack_is_loaded()) + { + btstack_stop(); + [self.topViewController.navigationItem setRightBarButtonItem:[self createBluetoothButton] animated:YES]; + } +} + +@end + +void ios_rarch_exited(void* result) +{ + [[RetroArch_iOS get] rarchExited:result ? NO : YES]; +}