diff --git a/apple/OSX/platform.h b/apple/OSX/platform.h
new file mode 100644
index 0000000000..f858ade962
--- /dev/null
+++ b/apple/OSX/platform.h
@@ -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 .
+ */
+
+#ifndef __RARCH_OSX_PLATFORM_H
+#define __RARCH_OSX_PLATFORM_H
+
+#import
+
+@interface RAGameView : NSOpenGLView
+
++ (RAGameView*)get;
+- (void)display;
+
+@end
+
+@interface RetroArch_OSX : NSObject
+{
+@public
+ NSWindow IBOutlet *window;
+}
+
++ (RetroArch_OSX*)get;
+
+- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file;
+- (void)unloadingCore:(RAModuleInfo*)core;
+
+@end
+
+#endif
diff --git a/apple/OSX/platform.m b/apple/OSX/platform.m
new file mode 100644
index 0000000000..b15d053e14
--- /dev/null
+++ b/apple/OSX/platform.m
@@ -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 .
+ */
+
+#include
+#include
+
+#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);
+}
+
diff --git a/apple/RetroArch/RetroArch_Apple.h b/apple/RetroArch/RetroArch_Apple.h
index 39096304d5..a714bb70c1 100644
--- a/apple/RetroArch/RetroArch_Apple.h
+++ b/apple/RetroArch/RetroArch_Apple.h
@@ -21,7 +21,8 @@
#import
#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 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
-
-+ (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
-
-@interface RAGameView : NSOpenGLView
-
-+ (RAGameView*)get;
-- (void)display;
-
-@end
-
-@interface RetroArch_OSX : NSObject
-{
-@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
diff --git a/apple/RetroArch/main.m b/apple/RetroArch/main.m
index 3e00e3c919..7d9f392040 100644
--- a/apple/RetroArch/main.m
+++ b/apple/RetroArch/main.m
@@ -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 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
diff --git a/apple/RetroArch_OSX.xcodeproj/project.pbxproj b/apple/RetroArch_OSX.xcodeproj/project.pbxproj
index e4b16ceb4a..6a1101970c 100644
--- a/apple/RetroArch_OSX.xcodeproj/project.pbxproj
+++ b/apple/RetroArch_OSX.xcodeproj/project.pbxproj
@@ -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;
};
diff --git a/apple/RetroArch_iOS.xcodeproj/project.pbxproj b/apple/RetroArch_iOS.xcodeproj/project.pbxproj
index 15081fd2eb..f94d43b805 100644
--- a/apple/RetroArch_iOS.xcodeproj/project.pbxproj
+++ b/apple/RetroArch_iOS.xcodeproj/project.pbxproj
@@ -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 = ""; };
+ 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 = ""; };
966B9CB916E41E7A005B61E1 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; };
966B9CBA16E41E7A005B61E1 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; };
@@ -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;
};
diff --git a/apple/iOS/platform.h b/apple/iOS/platform.h
new file mode 100644
index 0000000000..42c168884f
--- /dev/null
+++ b/apple/iOS/platform.h
@@ -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 .
+ */
+
+#ifndef __RARCH_IOS_PLATFORM_H
+#define __RARCH_IOS_PLATFORM_H
+
+@interface RAGameView : UIViewController
++ (RAGameView*)get;
+- (void)openPauseMenu;
+- (void)closePauseMenu;
+@end
+
+@interface RetroArch_iOS : UINavigationController
+
++ (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
\ No newline at end of file
diff --git a/apple/iOS/platform.m b/apple/iOS/platform.m
new file mode 100644
index 0000000000..74b6d5f16c
--- /dev/null
+++ b/apple/iOS/platform.m
@@ -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 .
+ */
+
+#include
+#include
+
+#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]));
+ }
+}
diff --git a/apple/iOS/settings.m b/apple/iOS/settings.m
index 797fe4c7ce..b386204a4c 100644
--- a/apple/iOS/settings.m
+++ b/apple/iOS/settings.m
@@ -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();
}
}