2013-08-14 10:07:36 -04:00
/ * RetroArch - A frontend for libretro .
2014-01-01 01:50:59 +01:00
* Copyright ( C ) 2013 -2014 - Jason Fetters
2013-08-14 10:07:36 -04:00
*
* RetroArch is free software : you can redistribute it and / or modify it under the terms
* of the GNU General Public License as published by the Free Software Found -
* ation , either version 3 of the License , or ( at your option ) any later version .
*
* RetroArch is distributed in the hope that it will be useful , but WITHOUT ANY WARRANTY ;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE . See the GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along with RetroArch .
* If not , see < http : // www . gnu . org / licenses / > .
* /
# include < string . h >
2013-11-22 15:30:02 +01:00
# include < objc / runtime . h >
2014-02-11 18:49:49 +11:00
# import "../common/RetroArch_Apple.h"
# include "../common/rarch_wrapper.h"
# include "../common/apple_input.h"
2013-08-14 10:07:36 -04:00
2014-02-11 18:52:28 +11:00
# include "../../file.h"
2013-08-14 10:07:36 -04:00
2013-12-13 19:23:22 -05:00
static void * const associated_core _key = ( void * ) & associated_core _key ;
2013-11-22 15:30:02 +01:00
2013-08-14 10:07:36 -04:00
@ interface RApplication : NSApplication
@ end
@ implementation RApplication
- ( void ) sendEvent : ( NSEvent * ) event
{
[ super sendEvent : event ] ;
2013-12-11 13:47:57 -05:00
2014-04-26 03:58:07 +02:00
NSEventType event_type = event . type ;
2013-12-14 20:35:47 -05:00
if ( event_type = = NSKeyDown || event_type = = NSKeyUp )
2014-01-09 18:16:20 -05:00
{
2014-04-26 03:58:07 +02:00
NSString * ch = ( NSString * ) event . characters ;
2014-01-09 18:16:20 -05:00
2014-04-26 03:58:07 +02:00
if ( ! ch || ch . length = = 0 )
apple_input _keyboard _event ( event_type = = NSKeyDown , event . keyCode , 0 , 0 ) ;
2014-01-09 18:16:20 -05:00
else
{
2014-04-26 03:58:07 +02:00
apple_input _keyboard _event ( event_type = = NSKeyDown , event . keyCode , [ ch characterAtIndex : 0 ] , event . modifierFlags ) ;
2014-01-09 18:16:20 -05:00
2014-04-26 03:58:07 +02:00
for ( unsigned i = 1 ; i ! = ch . length ; i + + )
apple_input _keyboard _event ( event_type = = NSKeyDown , 0 , [ ch characterAtIndex : i ] , event . modifierFlags ) ;
2014-01-09 18:16:20 -05:00
}
}
2013-12-14 20:35:47 -05:00
else if ( event_type = = NSFlagsChanged )
2013-12-11 13:47:57 -05:00
{
static uint32_t old_flags = 0 ;
2013-12-14 20:35:47 -05:00
uint32_t new_flags = [ event modifierFlags ] ;
2013-12-11 13:47:57 -05:00
bool down = ( new_flags & old_flags ) = = old_flags ;
old_flags = new_flags ;
2014-04-26 03:58:07 +02:00
apple_input _keyboard _event ( down , event . keyCode , 0 , event . modifierFlags ) ;
2013-12-11 13:47:57 -05:00
}
2013-12-14 20:35:47 -05:00
else if ( event_type = = NSMouseMoved || event_type = = NSLeftMouseDragged ||
event_type = = NSRightMouseDragged || event_type = = NSOtherMouseDragged )
2013-12-11 02:22:46 -05:00
{
// Relative
2014-04-26 03:58:07 +02:00
g_current _input _data . mouse_delta [ 0 ] + = event . deltaX ;
g_current _input _data . mouse_delta [ 1 ] + = event . deltaY ;
2013-12-11 02:22:46 -05:00
// Absolute
NSPoint pos = [ [ RAGameView get ] convertPoint : [ event locationInWindow ] fromView : nil ] ;
g_current _input _data . touches [ 0 ] . screen_x = pos . x ;
g_current _input _data . touches [ 0 ] . screen_y = pos . y ;
}
2013-12-14 20:35:47 -05:00
else if ( event_type = = NSLeftMouseDown || event_type = = NSRightMouseDown || event_type = = NSOtherMouseDown )
2013-12-11 02:22:46 -05:00
{
2014-04-26 03:58:07 +02:00
g_current _input _data . mouse_buttons | = 1 < < event . buttonNumber ;
2013-12-11 02:22:46 -05:00
g_current _input _data . touch_count = 1 ;
}
2013-12-14 20:35:47 -05:00
else if ( event_type = = NSLeftMouseUp || event_type = = NSRightMouseUp || event_type = = NSOtherMouseUp )
2013-12-11 02:22:46 -05:00
{
2014-04-26 03:58:07 +02:00
g_current _input _data . mouse_buttons & = ~ ( 1 < < event . buttonNumber ) ;
2013-12-11 02:22:46 -05:00
g_current _input _data . touch_count = 0 ;
}
2013-08-14 10:07:36 -04:00
}
@ end
2014-01-03 17:16:02 -05:00
static int waiting_argc ;
static char * * waiting_argv ;
2013-12-13 19:23:22 -05:00
@ interface RetroArch_OSX ( )
@ property ( nonatomic , retain ) NSWindowController * settingsWindow ;
@ property ( nonatomic , retain ) NSWindow IBOutlet * coreSelectSheet ;
@ property ( nonatomic , copy ) NSString * file ;
@ property ( nonatomic , copy ) NSString * core ;
@ end
2013-08-14 10:07:36 -04:00
@ implementation RetroArch_OSX
2013-12-13 19:23:22 -05:00
@ synthesize window = _window ;
@ synthesize configDirectory = _configDirectory ;
@ synthesize globalConfigFile = _globalConfigFile ;
@ synthesize coreDirectory = _coreDirectory ;
@ synthesize settingsWindow = _settingsWindow ;
@ synthesize coreSelectSheet = _coreSelectSheet ;
@ synthesize file = _file ;
@ synthesize core = _core ;
- ( void ) dealloc
{
[ _window release ] ;
[ _configDirectory release ] ;
[ _globalConfigFile release ] ;
[ _coreDirectory release ] ;
[ _coreSelectSheet release ] ;
[ _settingsWindow release ] ;
[ _file release ] ;
[ _core release ] ;
[ super dealloc ] ;
2013-08-14 10:07:36 -04:00
}
+ ( RetroArch_OSX * ) get
{
return ( RetroArch_OSX * ) [ [ NSApplication sharedApplication ] delegate ] ;
}
- ( void ) applicationDidFinishLaunching : ( NSNotification * ) aNotification
{
apple_platform = self ;
_loaded = true ;
2014-04-26 03:58:07 +02:00
NSArray * paths = ( NSArray * ) NSSearchPathForDirectoriesInDomains ( NSApplicationSupportDirectory , NSUserDomainMask , YES ) ;
self . configDirectory = [ [ paths objectAtIndex : 0 ] stringByAppendingPathComponent : BOXSTRING ( "RetroArch" ) ] ;
2014-04-26 04:49:47 +02:00
self . globalConfigFile = [ NSString stringWithFormat : BOXSTRING ( "%@/retroarch.cfg" ) , self . configDirectory ] ;
self . coreDirectory = [ [ [ NSBundle mainBundle ] bundlePath ] stringByAppendingPathComponent : BOXSTRING ( "Contents/Resources/modules" ) ] ;
2014-01-04 14:05:22 -05:00
# if __MAC _OS _X _VERSION _MAX _ALLOWED >= 1070
[ self . window setCollectionBehavior : [ self . window collectionBehavior ] | NSWindowCollectionBehaviorFullScreenPrimary ] ;
# endif
2013-12-14 20:35:47 -05:00
[ self . window setAcceptsMouseMovedEvents : YES ] ;
2013-12-13 19:23:22 -05:00
2013-12-14 20:35:47 -05:00
[ [ RAGameView get ] setFrame : [ [ self . window contentView ] bounds ] ] ;
[ [ self . window contentView ] setAutoresizesSubviews : YES ] ;
2014-04-26 04:49:47 +02:00
# if defined ( IOS ) || defined ( MAC_OS _X _VERSION _10 _5 )
2013-12-14 20:35:47 -05:00
[ [ self . window contentView ] addSubview : RAGameView . get ] ;
2014-02-22 13:49:41 +11:00
# endif
2013-12-14 20:35:47 -05:00
[ self . window makeFirstResponder : [ RAGameView get ] ] ;
2013-08-14 10:07:36 -04:00
2014-04-26 04:49:47 +02:00
self . settingsWindow = [ [ [ NSWindowController alloc ] initWithWindowNibName : BOXSTRING ( "Settings" ) ] autorelease ] ;
2013-08-14 10:07:36 -04:00
// Create core select list
2013-12-14 20:35:47 -05:00
NSComboBox * cb = ( NSComboBox * ) [ [ self . coreSelectSheet contentView ] viewWithTag : 1 ] ;
2013-11-22 15:30:02 +01:00
2014-04-26 03:58:07 +02:00
apple_core _info _set _core _path ( self . coreDirectory . UTF8String ) ;
apple_core _info _set _config _path ( self . configDirectory . UTF8String ) ;
const core_info _list _t * cores = ( const core_info _list _t * ) apple_core _info _list _get ( ) ;
2013-11-22 15:30:02 +01:00
for ( int i = 0 ; cores && i ! = cores -> count ; i + + )
{
2014-04-26 03:58:07 +02:00
NSString * desc = ( NSString * ) BOXSTRING ( cores -> list [ i ] . display_name ) ;
2014-04-14 18:30:21 +02:00
# if defined ( MAC_OS _X _VERSION _10 _6 )
/ * FIXME - Rewrite this so that this is no longer an associated object - requires ObjC 2.0 runtime * /
2013-11-22 15:30:02 +01:00
objc_setAssociatedObject ( desc , associated_core _key , apple_get _core _id ( & cores -> list [ i ] ) , OBJC_ASSOCIATION _RETAIN _NONATOMIC ) ;
2014-04-14 18:30:21 +02:00
# endif
[ cb addItemWithObjectValue : desc ] ;
2013-11-22 15:30:02 +01:00
}
2013-08-14 10:07:36 -04:00
2014-04-26 03:58:07 +02:00
if ( cb . numberOfItems )
2013-08-14 10:07:36 -04:00
[ cb selectItemAtIndex : 0 ] ;
else
2014-04-14 18:30:21 +02:00
apple_display _alert ( BOXSTRING ( "No libretro cores were found.\nSelect \" Go -> Cores Directory \ " from the menu and place libretro dylib files there." ) , BOXSTRING ( "RetroArch" ) ) ;
2013-11-22 15:30:02 +01:00
2014-01-03 17:16:02 -05:00
if ( waiting_argc )
{
apple_is _running = true ;
apple_rarch _load _content ( waiting_argc , waiting_argv ) ;
}
else if ( ! _wantReload )
2013-08-14 10:07:36 -04:00
apple_run _core ( nil , 0 ) ;
else
[ self chooseCore ] ;
2014-01-03 17:16:02 -05:00
waiting_argc = 0 ;
2013-08-14 10:07:36 -04:00
_wantReload = false ;
2013-12-11 02:22:46 -05:00
2014-01-03 17:16:02 -05:00
apple_start _iteration ( ) ;
2013-08-14 10:07:36 -04:00
extern void osx_pad _init ( ) ;
osx_pad _init ( ) ;
}
- ( BOOL ) applicationShouldTerminateAfterLastWindowClosed : ( NSApplication * ) theApplication
{
return YES ;
}
- ( NSApplicationTerminateReply ) applicationShouldTerminate : ( NSApplication * ) sender
{
_isTerminating = true ;
if ( apple_is _running )
2013-12-21 19:42:10 -05:00
apple_event _basic _command ( QUIT ) ;
2013-08-14 10:07:36 -04:00
return apple_is _running ? NSTerminateCancel : NSTerminateNow ;
}
- ( void ) application : ( NSApplication * ) sender openFiles : ( NSArray * ) filenames
{
2013-12-14 20:35:47 -05:00
if ( [ filenames count ] = = 1 && [ filenames objectAtIndex : 0 ] )
2013-08-14 10:07:36 -04:00
{
2013-12-13 19:23:22 -05:00
self . file = [ filenames objectAtIndex : 0 ] ;
2013-08-14 10:07:36 -04:00
if ( ! _loaded )
_wantReload = true ;
else
[ self chooseCore ] ;
[ sender replyToOpenOrPrint : NSApplicationDelegateReplySuccess ] ;
}
else
{
2014-04-26 04:49:47 +02:00
apple_display _alert ( BOXSTRING ( "Cannot open multiple files" ) , BOXSTRING ( "RetroArch" ) ) ;
2013-08-14 10:07:36 -04:00
[ sender replyToOpenOrPrint : NSApplicationDelegateReplyFailure ] ;
}
}
- ( void ) openDocument : ( id ) sender
{
NSOpenPanel * panel = [ NSOpenPanel openPanel ] ;
2014-04-26 04:49:47 +02:00
# if defined ( MAC_OS _X _VERSION _10 _5 )
2013-12-13 19:23:22 -05:00
[ panel beginSheetModalForWindow : self . window completionHandler : ^ ( NSInteger result )
2013-08-14 10:07:36 -04:00
{
2013-12-14 20:35:47 -05:00
[ [ NSApplication sharedApplication ] stopModal ] ;
2013-08-14 10:07:36 -04:00
2014-04-26 03:58:07 +02:00
if ( result = = NSOKButton && panel . URL )
2013-08-14 10:07:36 -04:00
{
2014-04-26 03:58:07 +02:00
NSURL * url = ( NSURL * ) panel . URL ;
self . file = url . path ;
2013-08-14 10:07:36 -04:00
[ self performSelector : @ selector ( chooseCore ) withObject : nil afterDelay : .5 f ] ;
}
} ] ;
2014-04-14 18:30:21 +02:00
# else
[ panel beginSheetForDirectory : nil file : nil modalForWindopw : [ self window ] modalDelegate : self didEndSelector : @ selector ( didEndSaveSheet : returnCode : contextInfo : ) contextInfo : NULL ] ;
# endif
2013-12-14 20:35:47 -05:00
[ [ NSApplication sharedApplication ] runModalForWindow : panel ] ;
2013-08-14 10:07:36 -04:00
}
2013-12-13 19:23:22 -05:00
// This utility function will queue the self . core and self . file instance values for running .
2013-08-14 10:07:36 -04:00
- ( void ) runCore
{
_wantReload = apple_is _running ;
if ( ! apple_is _running )
2014-04-26 03:58:07 +02:00
apple_run _core ( self . core , self . file . UTF8String ) ;
2013-08-14 10:07:36 -04:00
else
2013-12-21 19:42:10 -05:00
apple_event _basic _command ( QUIT ) ;
2013-08-14 10:07:36 -04:00
}
- ( void ) chooseCore
{
2013-12-14 20:35:47 -05:00
[ [ NSApplication sharedApplication ] beginSheet : self . coreSelectSheet modalForWindow : self . window modalDelegate : nil didEndSelector : nil contextInfo : nil ] ;
[ [ NSApplication sharedApplication ] runModalForWindow : self . coreSelectSheet ] ;
2013-08-14 10:07:36 -04:00
}
- ( IBAction ) coreWasChosen : ( id ) sender
{
2013-12-14 20:35:47 -05:00
[ [ NSApplication sharedApplication ] stopModal ] ;
[ [ NSApplication sharedApplication ] endSheet : self . coreSelectSheet returnCode : 0 ] ;
2013-12-13 19:23:22 -05:00
[ self . coreSelectSheet orderOut : self ] ;
2013-08-14 10:07:36 -04:00
if ( _isTerminating )
return ;
2013-12-14 20:35:47 -05:00
NSComboBox * cb = ( NSComboBox * ) [ [ self . coreSelectSheet contentView ] viewWithTag : 1 ] ;
2014-04-14 18:46:44 +02:00
# if defined ( MAC_OS _X _VERSION _10 _6 )
/ * FIXME - Rewrite this so that this is no longer an associated object - requires ObjC 2.0 runtime * /
2013-12-14 20:35:47 -05:00
self . core = objc_getAssociatedObject ( [ cb objectValueOfSelectedItem ] , associated_core _key ) ;
2014-04-14 18:46:44 +02:00
# endif
2013-08-14 10:07:36 -04:00
[ self runCore ] ;
}
# pragma mark RetroArch_Platform
2013-11-22 15:30:02 +01:00
- ( void ) loadingCore : ( const NSString * ) core withFile : ( const char * ) file
2013-08-14 10:07:36 -04:00
{
if ( file )
2013-12-14 20:35:47 -05:00
[ [ NSDocumentController sharedDocumentController ] noteNewRecentDocumentURL : [ NSURL fileURLWithPath : BOXSTRING ( file ) ] ] ;
2013-08-14 10:07:36 -04:00
}
2013-11-22 15:30:02 +01:00
- ( void ) unloadingCore : ( const NSString * ) core
2013-08-14 10:07:36 -04:00
{
if ( _isTerminating )
2013-12-14 20:35:47 -05:00
[ [ NSApplication sharedApplication ] terminate : nil ] ;
2013-08-14 10:07:36 -04:00
if ( _wantReload )
2014-04-26 03:58:07 +02:00
apple_run _core ( self . core , self . file . UTF8String ) ;
2013-08-14 10:07:36 -04:00
else if ( apple_use _tv _mode )
apple_run _core ( nil , 0 ) ;
else
2013-12-14 20:35:47 -05:00
[ [ NSApplication sharedApplication ] terminate : nil ] ;
2013-08-14 10:07:36 -04:00
_wantReload = false ;
}
# pragma mark Menus
2013-08-25 19:40:31 -04:00
- ( IBAction ) showCoresDirectory : ( id ) sender
{
2013-09-09 19:25:34 -04:00
[ [ NSWorkspace sharedWorkspace ] openFile : self . coreDirectory ] ;
2013-08-25 19:40:31 -04:00
}
2013-08-14 10:07:36 -04:00
- ( IBAction ) showPreferences : ( id ) sender
{
2013-12-14 20:35:47 -05:00
[ NSApp runModalForWindow : [ self . settingsWindow window ] ] ;
2013-08-14 10:07:36 -04:00
}
- ( IBAction ) basicEvent : ( id ) sender
{
if ( apple_is _running )
2013-12-21 19:42:10 -05:00
apple_event _basic _command ( [ sender tag ] ) ;
2013-08-14 10:07:36 -04:00
}
- ( void ) alertDidEnd : ( NSAlert * ) alert returnCode : ( NSInteger ) returnCode contextInfo : ( void * ) contextInfo
{
2013-12-14 20:35:47 -05:00
[ [ NSApplication sharedApplication ] stopModal ] ;
2013-08-14 10:07:36 -04:00
}
@ end
int main ( int argc , char * argv [ ] )
{
2013-08-27 12:07:59 -04:00
for ( int i = 0 ; i ! = argc ; i + + )
if ( strcmp ( argv [ i ] , "--" ) = = 0 )
{
2014-01-03 17:16:02 -05:00
waiting_argc = argc - i ;
waiting_argv = argv + i ;
break ;
2013-08-27 12:07:59 -04:00
}
2013-08-14 10:07:36 -04:00
return NSApplicationMain ( argc , ( const char * * ) argv ) ;
}