summaryrefslogtreecommitdiff
path: root/macosx/Source/PcsxrController.m
diff options
context:
space:
mode:
authorSND\MaddTheSane_cp <SND\MaddTheSane_cp@e17a0e51-4ae3-4d35-97c3-1a29b211df97>2014-07-20 05:09:43 +0000
committerSND\MaddTheSane_cp <SND\MaddTheSane_cp@e17a0e51-4ae3-4d35-97c3-1a29b211df97>2014-07-20 05:09:43 +0000
commitd6942932d64a02aa92b1e04e91f6126f33fdb05e (patch)
tree7cad698308e39abc2b0e1c71674c610ec3ce74dd /macosx/Source/PcsxrController.m
parentb8d0d24d56dbc0ee64f4ec9a72ab917604d8109d (diff)
downloadpcsxr-d6942932d64a02aa92b1e04e91f6126f33fdb05e.tar.gz
OS X: Move source files to their own folder.
git-svn-id: https://pcsxr.svn.codeplex.com/svn/pcsxr@90999 e17a0e51-4ae3-4d35-97c3-1a29b211df97
Diffstat (limited to 'macosx/Source/PcsxrController.m')
-rw-r--r--macosx/Source/PcsxrController.m974
1 files changed, 974 insertions, 0 deletions
diff --git a/macosx/Source/PcsxrController.m b/macosx/Source/PcsxrController.m
new file mode 100644
index 00000000..4bdce477
--- /dev/null
+++ b/macosx/Source/PcsxrController.m
@@ -0,0 +1,974 @@
+#import <Cocoa/Cocoa.h>
+#import "PcsxrController.h"
+#import "ConfigurationController.h"
+#import "CheatController.h"
+#import "EmuThread.h"
+#import "PcsxrMemCardHandler.h"
+#import "PcsxrPluginHandler.h"
+#import "PcsxrDiscHandler.h"
+#import "PcsxrFreezeStateHandler.h"
+#import "PcsxrCheatHandler.h"
+#import "LaunchArg.h"
+#include <DiskArbitration/DiskArbitration.h>
+#include <IOKit/storage/IOCDMedia.h>
+#include "psxcommon.h"
+#include "plugins.h"
+#include "misc.h"
+#include "cdrom.h"
+#include "ExtendedKeys.h"
+
+NSDictionary *prefStringKeys = nil;
+NSDictionary *prefByteKeys = nil;
+NSDictionary *prefURLKeys = nil;
+NSMutableArray *biosList = nil;
+NSString *saveStatePath = nil;
+BOOL wasFinderLaunch = NO;
+
+
+#define HELPSTR "\n" \
+"At least one of these must be passed:\n" \
+"\t--iso path launch with selected ISO\n" \
+"\t--cdrom launch with a CD-ROM\n" \
+"\t--bios launch into the BIOS\n" \
+"\n" \
+"Additional options:\n" \
+"\t--exitAtClose closes PCSX-R at when the emulation has ended\n" \
+"\t--mcd1 path sets the fist memory card to path\n" \
+"\t--mcd2 path sets the second memory card to path\n" \
+"\t--freeze path loads freeze state from path\n" \
+"\n" \
+"Help:\n" \
+"\t--help shows this message\n" \
+"\n" \
+
+
+void ShowHelpAndExit(FILE* output, int exitCode)
+{
+ fprintf(output, HELPSTR);
+ if (!NSApp) {
+ exit(exitCode);
+ } else {
+ [NSApp stop:nil];
+ }
+}
+
+@interface PcsxrController ()
+@property (readwrite) BOOL endAtEmuClose;
+@property BOOL sleepInBackground;
+@property BOOL wasPausedBeforeBGSwitch;
+@property BOOL wasPausedBeforeDiscEject;
+@property (strong) NSMutableArray *skipFiles;
+@property (strong) NSWindow *preferenceWindow;
+@property (strong) NSWindow *cheatWindow;
+@property (nonatomic) DASessionRef diskSession;
+@end
+
+@implementation PcsxrController
+@synthesize recentItems;
+@synthesize skipFiles;
+@synthesize cheatController;
+@synthesize cheatWindow;
+@synthesize preferenceWindow;
+
+- (BOOL)endAtEmuClose
+{
+ return PSXflags.endAtEmuClose;
+}
+
+- (void)setEndAtEmuClose:(BOOL)endAtEmuClose
+{
+ PSXflags.endAtEmuClose = endAtEmuClose;
+}
+
+- (BOOL)sleepInBackground
+{
+ return PSXflags.sleepInBackground;
+}
+
+- (void)setSleepInBackground:(BOOL)sleepInBackground
+{
+ PSXflags.sleepInBackground = sleepInBackground;
+}
+
+- (BOOL)wasPausedBeforeBGSwitch
+{
+ return PSXflags.wasPausedBeforeBGSwitch;
+}
+
+- (void)setWasPausedBeforeBGSwitch:(BOOL)wasPausedBeforeBGSwitch
+{
+ PSXflags.wasPausedBeforeBGSwitch = wasPausedBeforeBGSwitch;
+}
+
+- (BOOL)wasPausedBeforeDiscEject
+{
+ return PSXflags.wasPausedBeforeDiscEject;
+}
+
+-(void)setWasPausedBeforeDiscEject:(BOOL)wasPausedBeforeDiscEject
+{
+ PSXflags.wasPausedBeforeDiscEject = wasPausedBeforeDiscEject;
+}
+
+@synthesize diskSession = _diskSession;
+- (void)setDiskSession:(DASessionRef)diskSession
+{
+ if (diskSession == _diskSession) {
+ return;
+ }
+ if (_diskSession) {
+ CFRelease(_diskSession);
+ _diskSession = NULL;
+ }if (diskSession) {
+ _diskSession = diskSession;
+ CFRetain(diskSession);
+ }
+}
+
+static void PSXDiscAppearedCallback(DADiskRef disk, void *context)
+{
+ PcsxrController *theSelf = (__bridge PcsxrController*)context;
+ //sleep(3); //Is this needed?
+ SetCdOpenCaseTime(time(NULL) + 2);
+ LidInterrupt();
+
+ /* and open new cd */
+ if ([EmuThread active])
+ CDR_open();
+
+ if (!theSelf.wasPausedBeforeDiscEject) {
+ [EmuThread resume];
+ }
+
+ DASessionUnscheduleFromRunLoop(theSelf.diskSession, CFRunLoopGetMain(), kCFRunLoopCommonModes);
+ theSelf.diskSession = NULL;
+}
+
+- (IBAction)ejectCD:(id)sender
+{
+ self.wasPausedBeforeDiscEject = [EmuThread pauseSafe];
+
+ /* close connection to current cd */
+ if ([EmuThread active])
+ CDR_close();
+
+ // switch to another ISO if using internal image reader, otherwise eject the CD
+ if (UsingIso()) {
+ NSOpenPanel* openDlg = [NSOpenPanel openPanel];
+ [openDlg setAllowedFileTypes:[PcsxrDiscHandler supportedUTIs]];
+
+ if ([openDlg runModal] == NSFileHandlingPanelOKButton) {
+ NSArray* files = [openDlg URLs];
+ SetIsoFile([[files[0] path] fileSystemRepresentation]);
+ SetCdOpenCaseTime(time(NULL) + 2);
+ LidInterrupt();
+ }
+
+ if ([EmuThread active])
+ CDR_open();
+
+ if (!self.wasPausedBeforeDiscEject) {
+ [EmuThread resume];
+ }
+ } else {
+ NSMutableString *deviceName;
+ NSTask *ejectTask;
+ NSRange rdiskRange;
+ char *driveLetter = CDR_getDriveLetter();
+
+ if (driveLetter != NULL) {
+ deviceName = [NSMutableString stringWithString:[[NSFileManager defaultManager] stringWithFileSystemRepresentation:driveLetter length:strlen(driveLetter)]];
+
+ // delete the 'r' in 'rdisk'
+ rdiskRange = [deviceName rangeOfString:@"rdisk"];
+ if (rdiskRange.length != 0) {
+ rdiskRange.length = 1;
+ [deviceName deleteCharactersInRange:rdiskRange];
+ }
+ // execute hdiutil to eject the device
+ ejectTask = [NSTask launchedTaskWithLaunchPath:@"/usr/bin/hdiutil" arguments:@[@"eject", deviceName]];
+ [ejectTask waitUntilExit];
+ }
+ DASessionRef tmpSession = DASessionCreate(kCFAllocatorDefault);
+ CFDictionaryRef match = CFBridgingRetain(@{(NSString*)kDADiskDescriptionMediaKindKey : @(kIOCDMediaClass),
+ (NSString*)kDADiskDescriptionMediaWholeKey : @YES});
+ DARegisterDiskAppearedCallback(tmpSession, match, PSXDiscAppearedCallback, (__bridge void*)self);
+ CFRelease(match);
+
+ DASessionScheduleWithRunLoop(tmpSession, CFRunLoopGetMain(), kCFRunLoopCommonModes);
+
+ self.diskSession = tmpSession;
+ CFRelease(tmpSession);
+ }
+}
+
+- (void)emuWindowDidClose:(NSNotification*)theNot
+{
+ if (self.diskSession) {
+ DASessionUnscheduleFromRunLoop(self.diskSession, CFRunLoopGetMain(), kCFRunLoopCommonModes);
+ self.diskSession = NULL;
+ }
+}
+
+- (IBAction)pause:(id)sender
+{
+ if ([EmuThread isPaused]) {
+ //[sender setState:NSOffState];
+ [EmuThread resume];
+ }
+ else {
+ //[sender setState:NSOnState];
+ [EmuThread pause];
+ }
+}
+
+- (IBAction)showCheatsWindow:(id)sender
+{
+ /* load the nib if it hasn't yet */
+ if (cheatWindow == nil) {
+ if (cheatController == nil) {
+ cheatController = [[CheatController alloc] initWithWindowNibName:@"CheatWindow"];
+ }
+ cheatWindow = [cheatController window];
+ }
+
+ /* show the window */
+ [cheatController showWindow:sender];
+}
+
+- (IBAction)preferences:(id)sender
+{
+ /* load the nib if it hasn't yet */
+ if (preferenceWindow == nil) {
+ if (preferencesController == nil) {
+ preferencesController = [[ConfigurationController alloc] initWithWindowNibName:@"Configuration"];
+ }
+ preferenceWindow = [preferencesController window];
+ }
+
+ /* show the window */
+ [preferencesController showWindow:sender];
+}
+
+- (IBAction)reset:(id)sender
+{
+ [EmuThread reset];
+}
+
+- (IBAction)runCD:(id)sender
+{
+ SetIsoFile(NULL);
+ if ([[NSUserDefaults standardUserDefaults] boolForKey:@"NetPlay"]) {
+ [pluginList enableNetPlug];
+ } else {
+ [pluginList disableNetPlug];
+ }
+ [EmuThread run];
+}
+
+- (IBAction)runIso:(id)sender
+{
+ NSOpenPanel* openDlg = [NSOpenPanel openPanel];
+ [openDlg setAllowedFileTypes:[PcsxrDiscHandler supportedUTIs]];
+
+ if ([openDlg runModal] == NSFileHandlingPanelOKButton) {
+ NSURL *url = [openDlg URLs][0];
+ [recentItems addRecentItem:url];
+ [self runURL:url];
+ }
+}
+
+- (IBAction)runBios:(id)sender
+{
+ SetIsoFile(NULL);
+ [pluginList disableNetPlug];
+ [EmuThread runBios];
+}
+
+- (void)runURL:(NSURL*)url
+{
+ if ([EmuThread active] == YES) {
+ if (UsingIso()) {
+ SetIsoFile([[url path] fileSystemRepresentation]);
+ SetCdOpenCaseTime(time(NULL) + 2);
+ LidInterrupt();
+ } else {
+ NSBeep();
+ }
+ } else {
+ if ([[NSUserDefaults standardUserDefaults] boolForKey:@"NetPlay"]) {
+ [pluginList enableNetPlug];
+ } else {
+ [pluginList disableNetPlug];
+ }
+ SetIsoFile([[url path] fileSystemRepresentation]);
+ [EmuThread run];
+ }
+}
+
+- (IBAction)freeze:(id)sender
+{
+ NSInteger num = [sender tag];
+ [PcsxrController saveState:(int)num];
+}
+
++ (void)saveState:(int)num
+{
+ [EmuThread freezeAt:[PcsxrController saveStatePath:num] which:num];
+}
+
+- (IBAction)defrost:(id)sender
+{
+ NSInteger num = [sender tag];
+ [PcsxrController loadState:(int)num];
+}
+
++ (void)loadState:(int)num
+{
+ [EmuThread defrostAt:[PcsxrController saveStatePath:num]];
+}
+
+- (IBAction)fullscreen:(id)sender
+{
+ GPU_keypressed(GPU_FULLSCREEN_KEY);
+}
+
+- (IBAction)pauseInBackground:(id)sender
+{
+ self.sleepInBackground = !self.sleepInBackground;
+ [[NSUserDefaults standardUserDefaults] setBool:self.sleepInBackground forKey:@"PauseInBackground"];
+}
+
+- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
+{
+ if ([menuItem action] == @selector(pause:)) {
+ [menuItem setState:([EmuThread isPaused] ? NSOnState : NSOffState)];
+ }
+
+ if ([menuItem action] == @selector(pause:) || [menuItem action] == @selector(fullscreen:))
+ return [EmuThread active];
+
+ if ([menuItem action] == @selector(reset:) || [menuItem action] == @selector(ejectCD:) ||
+ [menuItem action] == @selector(freeze:))
+ return [EmuThread active] && ![EmuThread isRunBios];
+
+ if ([menuItem action] == @selector(runCD:) || [menuItem action] == @selector(runIso:) ||
+ [menuItem action] == @selector(runBios:)) {
+ if (preferenceWindow != nil)
+ if ([preferenceWindow isVisible])
+ return NO;
+
+ if (cheatWindow != nil)
+ if ([cheatWindow isVisible])
+ return NO;
+
+ if ([menuItem action] == @selector(runBios:) && strcmp(Config.Bios, "HLE") == 0)
+ return NO;
+
+ return ![EmuThread active];
+ }
+
+ if ([menuItem action] == @selector(defrost:)) {
+ if (![EmuThread active] || [EmuThread isRunBios])
+ return NO;
+
+ NSString *path = [saveStatePath stringByAppendingPathComponent:[NSString stringWithFormat:@"%s-%3.3ld.pcsxrstate", CdromId, (long)[menuItem tag]]];
+ return (CheckState((char *)[path fileSystemRepresentation]) == 0);
+ }
+
+ if ([menuItem action] == @selector(preferences:))
+ return ![EmuThread active];
+
+ if ([menuItem action] == @selector(pauseInBackground:)) {
+ [menuItem setState:(self.sleepInBackground ? NSOnState : NSOffState)];
+ return YES;
+ }
+
+ return YES;
+}
+
+- (void)applicationWillResignActive:(NSNotification *)aNotification
+{
+ self.wasPausedBeforeBGSwitch = [EmuThread isPaused];
+
+ if (self.sleepInBackground) {
+ [EmuThread pause];
+ }
+}
+
+- (void)applicationDidBecomeActive:(NSNotification *)aNotification
+{
+ if (self.sleepInBackground && !self.wasPausedBeforeBGSwitch) {
+ [EmuThread resume];
+ }
+}
+
+- (void)applicationDidFinishLaunching:(NSNotification *)notification
+{
+ self.skipFiles = nil;
+}
+
+static void ParseErrorStr(NSString *errStr)
+{
+ NSLog(@"Parse error: %@", errStr);
+ NSRunCriticalAlertPanel(@"Parsing error", @"%@\n\nPlease check the command line options and try again.\n\nPCSXR will now quit.", nil, nil, nil, errStr);
+ ShowHelpAndExit(stderr, EXIT_FAILURE);
+}
+
+//DO NOT END THIS MACRO WITH A SIMICOLON! it will break the if-else if process
+#define HandleArg(arg, launchable, otherblock) \
+if ([[progArgs objectAtIndex:i] compare:arg options:NSCaseInsensitiveSearch] == NSOrderedSame) { \
+HandleArgBase(arg, launchable, otherblock)
+
+#define HandleArgElse(arg, launchable, otherblock) \
+else if ([[progArgs objectAtIndex:i] compare:arg options:NSCaseInsensitiveSearch] == NSOrderedSame) { \
+HandleArgBase(arg, launchable, otherblock)
+
+#define HandleArgBase(arg, launchable, otherblock) \
+if (isLaunchable && launchable) { \
+ParseErrorStr([NSString stringWithFormat:@"The options %@ and %@ are exclusive.", arg, runtimeStr]); \
+} \
+if(launchable) { \
+isLaunchable = YES; \
+runtimeStr = arg; \
+} \
+otherblock();\
+}
+
+#define kPCSXRArgumentCDROM @"--cdrom"
+#define kPCSXRArgumentBIOS @"--bios"
+#define kPCSXRArgumentISO @"--iso"
+#define kPCSXRArgumentMcd @"--mcd"
+#define kPCSXRArgumentMcd1 kPCSXRArgumentMcd @"1"
+#define kPCSXRArgumentMcd2 kPCSXRArgumentMcd @"2"
+#define kPCSXRArgumentFreeze @"--freeze"
+#define kPCSXRArgumentExitAtClose @"--exitAtClose"
+
+- (void)dealloc
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)awakeFromNib
+{
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self selector:@selector(emuWindowDidClose:)
+ name:@"emuWindowDidClose" object:nil];
+
+ pluginList = [[PluginList alloc] init];
+ if (![pluginList configured] /*!Config.Gpu[0] || !Config.Spu[0] || !Config.Pad1[0] || !Config.Cdr[0]*/) {
+ // configure plugins
+ [self preferences:nil];
+
+ NSRunCriticalAlertPanel(NSLocalizedString(@"Missing plugins!", nil),
+ NSLocalizedString(@"Pcsxr is missing one or more critical plugins. You will need to install these in order to play games.", nil),
+ nil, nil, nil);
+ }
+
+ if (![PcsxrController biosAvailable]) {
+ NSFileManager *manager = [NSFileManager defaultManager];
+ NSURL *supportURL = [manager URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:NULL];
+ NSURL *biosURL = [[supportURL URLByAppendingPathComponent:@"Pcsxr"] URLByAppendingPathComponent:@"Bios"];
+ NSInteger retVal = NSRunInformationalAlertPanel(NSLocalizedString(@"Missing BIOS!", nil),
+ NSLocalizedString(@"Pcsxr wasn't able to locate any Playstation BIOS ROM files. This means that it will run in BIOS simulation mode which is less stable and compatible than using a real Playstation BIOS.\nIf you have a BIOS available, please copy it to\n%@", nil),
+ NSLocalizedString(@"Okay", @"OK"), NSLocalizedString(@"Show Folder", @"Show Folder"), nil, [[biosURL path] stringByAbbreviatingWithTildeInPath]);
+ if (retVal == NSAlertAlternateReturn) {
+ [[NSWorkspace sharedWorkspace] activateFileViewerSelectingURLs:@[biosURL]];
+ }
+ }
+
+ self.sleepInBackground = [[NSUserDefaults standardUserDefaults] boolForKey:@"PauseInBackground"];
+
+ NSArray *progArgs = [[NSProcessInfo processInfo] arguments];
+ if ([progArgs count] > 1 && !wasFinderLaunch) {
+ self.skipFiles = [NSMutableArray array];
+
+ BOOL isLaunchable = NO;
+ NSString *runtimeStr = nil;
+
+ __block short memcardHandled = 0;
+ __block BOOL hasParsedAnArgument = NO;
+ __block NSString *(^FileTestBlock)() = NULL;
+ __block NSMutableDictionary *argDict = [[NSMutableDictionary alloc] initWithCapacity:[progArgs count]];
+
+
+ NSMutableArray *unknownOptions = [NSMutableArray array];
+
+ dispatch_block_t cdromBlock = ^{
+ hasParsedAnArgument = YES;
+ LaunchArg *larg = [[LaunchArg alloc] initWithLaunchOrder:LaunchArgRun argument:kPCSXRArgumentCDROM block:^{
+ [self runCD:nil];
+ }];
+ [larg addToDictionary:argDict];
+ };
+
+ dispatch_block_t biosBlock = ^{
+ hasParsedAnArgument = YES;
+ LaunchArg *larg = [[LaunchArg alloc] initWithLaunchOrder:LaunchArgRun argument:kPCSXRArgumentBIOS block:^{
+ [self runBios:nil];
+ }];
+ [larg addToDictionary:argDict];
+ };
+
+ //This block/argument does not need to be sorted
+ dispatch_block_t emuCloseAtEnd = ^{
+ hasParsedAnArgument = YES;
+ LaunchArg *larg = [[LaunchArg alloc] initWithLaunchOrder:LaunchArgPreRun argument:kPCSXRArgumentExitAtClose block:^{
+ self.endAtEmuClose = YES;
+ }];
+ [larg addToDictionary:argDict];
+ };
+
+ dispatch_block_t isoBlock = ^{
+ hasParsedAnArgument = YES;
+ NSString *path = FileTestBlock();
+ LaunchArg *larg = [[LaunchArg alloc] initWithLaunchOrder:LaunchArgRun argument:kPCSXRArgumentISO block:^{
+ [self runURL:[NSURL fileURLWithPath:path isDirectory:NO]];
+ }];
+ [larg addToDictionary:argDict];
+ };
+
+ void (^mcdBlock)(int mcdNumber) = ^(int mcdnumber){
+ hasParsedAnArgument = YES;
+ if (memcardHandled & (1 << mcdnumber)) {
+ NSLog(@"Memory card %i has already been defined. The latest one passed will be used.", mcdnumber);
+ } else {
+ memcardHandled |= (1 << mcdnumber);
+ }
+
+ NSString *path = FileTestBlock();
+ NSString *mcdArg = [kPCSXRArgumentMcd stringByAppendingFormat:@"%i", mcdnumber];
+ LaunchArg *larg = [[LaunchArg alloc] initWithLaunchOrder:LaunchArgPreRun argument:mcdArg block:^{
+ LoadMcd(mcdnumber, (char*)[path fileSystemRepresentation]);
+ }];
+ [larg addToDictionary:argDict];
+ };
+
+ dispatch_block_t freezeBlock = ^{
+ hasParsedAnArgument = YES;
+ NSString *path = FileTestBlock();
+ LaunchArg *larg = [[LaunchArg alloc] initWithLaunchOrder:LaunchArgPostRun argument:kPCSXRArgumentFreeze block:^{
+ if (![EmuThread isRunBios]) {
+ //Make sure the emulator is running
+ sleep(5);
+ [EmuThread defrostAt:path];
+ }
+ }];
+ [larg addToDictionary:argDict];
+ };
+
+ BOOL hasFileTestBlock = NO;
+
+ for (__block int i = 1; i < [progArgs count]; i++) {
+ if (!hasFileTestBlock)
+ {
+ FileTestBlock = ^NSString *(){
+ if ([progArgs count] <= ++i) {
+ ParseErrorStr(@"Not enough arguments.");
+ }
+ NSString *path = [progArgs[i] stringByExpandingTildeInPath];
+ if (![[NSFileManager defaultManager] fileExistsAtPath:path])
+ {
+ ParseErrorStr([NSString stringWithFormat:@"The file \"%@\" does not exist.", path]);
+ return nil;
+ }
+ [skipFiles addObject:path];
+ return path;
+ };
+ hasFileTestBlock = YES;
+ }
+
+ //DO NOT END these MACROS WITH A SIMICOLON! It will break the if-else if process
+ HandleArg(kPCSXRArgumentISO, YES, isoBlock)
+ HandleArgElse(kPCSXRArgumentCDROM, YES, cdromBlock)
+ HandleArgElse(kPCSXRArgumentBIOS, YES, biosBlock)
+ HandleArgElse(kPCSXRArgumentExitAtClose, NO, emuCloseAtEnd)
+ HandleArgElse(kPCSXRArgumentMcd1, NO, ^{mcdBlock(1);})
+ HandleArgElse(kPCSXRArgumentMcd2, NO, ^{mcdBlock(2);})
+ HandleArgElse(kPCSXRArgumentFreeze, NO, freezeBlock)
+ else {
+ [unknownOptions addObject:progArgs[i]];
+ }
+ }
+#ifdef DEBUG
+ if ([unknownOptions count]) {
+ NSString *unknownString = [unknownOptions componentsJoinedByString:@" "];
+
+ NSLog(@"The following options weren't recognized by PCSX-R: %@. This may be due to extra arguments passed by the OS or debugger.", unknownString);
+ }
+#endif
+ unknownOptions = nil;
+ if (!isLaunchable && hasParsedAnArgument) {
+ NSMutableArray *mutProgArgs = [NSMutableArray arrayWithArray:progArgs];
+ NSString *appRawPath = mutProgArgs[0];
+ //Remove the app file path from the array
+ [mutProgArgs removeObjectAtIndex:0];
+ NSString *arg = [mutProgArgs componentsJoinedByString:@" "];
+ NSString *recognizedArgs = [[argDict allKeys] componentsJoinedByString:@" "];
+
+ NSString *tmpStr = [NSString stringWithFormat:@"A launch command wasn't found in the command line and one or more arguments that PCSX-R recognizes were: %@.\nThe following command line arguments were passed with the application launch file at %@: %@.\n\nThe valid launch commands are %@, %@, and %@.", recognizedArgs, appRawPath, arg, kPCSXRArgumentISO, kPCSXRArgumentCDROM, kPCSXRArgumentBIOS];
+ ParseErrorStr(tmpStr);
+ } else if (hasParsedAnArgument){
+ NSArray *argArray = [[argDict allValues] sortedArrayWithOptions:NSSortStable usingComparator:^NSComparisonResult(id obj1, id obj2) {
+ LaunchArg *LA1 = obj1;
+ LaunchArg *LA2 = obj2;
+ if (LA1.launchOrder > LA2.launchOrder) {
+ return NSOrderedDescending;
+ } else if (LA1.launchOrder < LA2.launchOrder) {
+ return NSOrderedAscending;
+ } else {
+ return NSOrderedSame;
+ }
+ }];
+ for (LaunchArg *arg in argArray) {
+ arg.theBlock();
+ }
+ }
+ }
+}
+
++ (void)setConfigFromDefaults
+{
+ const char *str;
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+
+ /*
+ enumerator = [prefStringKeys keyEnumerator];
+ while ((key = [enumerator nextObject])) {
+ str = [[defaults stringForKey:key] fileSystemRepresentation];
+ char *dst = (char *)[[prefStringKeys objectForKey:key] pointerValue];
+ if (str != nil && dst != nil) strncpy(dst, str, 255);
+ }*/
+
+ for (NSString *key in prefByteKeys) {
+ u8 *dst = (u8 *)[prefByteKeys[key] pointerValue];
+ if (dst != NULL) *dst = [defaults boolForKey:key];
+ }
+
+ // special cases
+ //str = [[defaults stringForKey:@"PluginPAD"] fileSystemRepresentation];
+ //if (str != nil) strncpy(Config.Pad2, str, 255);
+
+ str = [[defaults stringForKey:@"Bios"] fileSystemRepresentation];
+ if (str) {
+ NSString *path = [defaults stringForKey:@"Bios"];
+ NSInteger index = [biosList indexOfObject:path];
+
+ if (-1 == index) {
+ [biosList insertObject:path atIndex:0];
+ } else if (0 < index) {
+ [biosList exchangeObjectAtIndex:index withObjectAtIndex:0];
+ }
+ }
+
+ {
+ NSFileManager *manager = [NSFileManager defaultManager];
+ NSURL *memoryURL = [[[manager URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:NULL] URLByAppendingPathComponent:@"Pcsxr"] URLByAppendingPathComponent:@"Memory Cards"];
+
+ str = [[[defaults URLForKey:@"Mcd1"] path] fileSystemRepresentation];
+ if (str) {
+ strlcpy(Config.Mcd1, str, MAXPATHLEN);
+ } else {
+ NSURL *url = [memoryURL URLByAppendingPathComponent:@"Mcd001.mcr"];
+ [defaults setURL:url forKey:@"Mcd1"];
+ str = [[url path] fileSystemRepresentation];
+ if (str != nil) strlcpy(Config.Mcd1, str, MAXPATHLEN);
+ }
+
+ str = [[[defaults URLForKey:@"Mcd2"] path] fileSystemRepresentation];
+ if (str) {
+ strlcpy(Config.Mcd2, str, MAXPATHLEN);
+ } else {
+ NSURL *url = [memoryURL URLByAppendingPathComponent:@"Mcd002.mcr"];
+ [defaults setURL:url forKey:@"Mcd2"];
+ str = [[url path] fileSystemRepresentation];
+ if (str != nil) strlcpy(Config.Mcd2, str, MAXPATHLEN);
+ }
+ }
+
+ if ([defaults boolForKey:@"UseHLE"] || 0 == [biosList count]) {
+ strcpy(Config.Bios, "HLE");
+ } else {
+ str = [(NSString *)biosList[0] fileSystemRepresentation];
+ if (str != nil) strlcpy(Config.Bios, str, MAXPATHLEN);
+ else strcpy(Config.Bios, "HLE");
+ }
+
+ str = [[defaults stringForKey:@"Net"] fileSystemRepresentation];
+ if (str) strlcpy(Config.Net, str, MAXPATHLEN);
+ else {
+ strcpy(Config.Net, "Disabled");
+ }
+}
+
++ (void)setDefaultFromConfig:(NSString *)defaultKey
+{
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+
+ char *str = (char *)[prefStringKeys[defaultKey] pointerValue];
+ if (str) {
+ NSString *tmpNSStr = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:str length:strlen(str)];
+ if (!tmpNSStr) {
+ tmpNSStr = @(str);
+ }
+
+ [defaults setObject:tmpNSStr forKey:defaultKey];
+ return;
+ }
+
+ str = (char *)[prefURLKeys[defaultKey] pointerValue];
+ if (str) {
+ NSString *tmpNSStr = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:str length:strlen(str)];
+ if (!tmpNSStr) {
+ tmpNSStr = @(str);
+ }
+ [defaults setURL:[NSURL fileURLWithPath:tmpNSStr isDirectory:NO] forKey:defaultKey];
+ return;
+ }
+
+ u8 *val = (u8 *)[prefByteKeys[defaultKey] pointerValue];
+ if (val) {
+ [defaults setInteger:*val forKey:defaultKey];
+ return;
+ }
+}
+
++ (BOOL)biosAvailable
+{
+ return ([biosList count] > 0);
+}
+
+// called when class is initialized
++ (void)initialize
+{
+ NSString *path;
+ const char *str;
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+ NSDictionary *appDefaults = @{@"NoDynarec": @YES,
+ @"AutoDetectVideoType": @YES,
+ @"UseHLE": @NO,
+ @"PauseInBackground": @YES,
+ @"Widescreen": @NO,
+ @"NetPlay": @NO};
+
+ [defaults registerDefaults:appDefaults];
+
+ prefStringKeys = @{@"PluginGPU": [NSValue valueWithPointer:Config.Gpu],
+ @"PluginSPU": [NSValue valueWithPointer:Config.Spu],
+ @"PluginPAD": [NSValue valueWithPointer:Config.Pad1],
+ @"PluginCDR": [NSValue valueWithPointer:Config.Cdr],
+ @"PluginNET": [NSValue valueWithPointer:Config.Net],
+ @"PluginSIO1": [NSValue valueWithPointer:Config.Sio1]};
+
+ prefURLKeys = @{@"Mcd1": [NSValue valueWithPointer:Config.Mcd1],
+ @"Mcd2": [NSValue valueWithPointer:Config.Mcd2]};
+
+ prefByteKeys = @{@"NoXaAudio": [NSValue valueWithPointer:&Config.Xa],
+ @"SioIrqAlways": [NSValue valueWithPointer:&Config.SioIrq],
+ @"BlackAndWhiteMDECVideo": [NSValue valueWithPointer:&Config.Mdec],
+ @"AutoDetectVideoType": [NSValue valueWithPointer:&Config.PsxAuto],
+ @"VideoTypePAL": [NSValue valueWithPointer:&Config.PsxType],
+ @"NoCDAudio": [NSValue valueWithPointer:&Config.Cdda],
+ @"NoDynarec": [NSValue valueWithPointer:&Config.Cpu],
+ @"ConsoleOutput": [NSValue valueWithPointer:&Config.PsxOut],
+ @"SpuIrqAlways": [NSValue valueWithPointer:&Config.SpuIrq],
+ @"RootCounterFix": [NSValue valueWithPointer:&Config.RCntFix],
+ @"VideoSyncWAFix": [NSValue valueWithPointer:&Config.VSyncWA],
+ @"Widescreen": [NSValue valueWithPointer:&Config.Widescreen]};
+
+ // setup application support paths
+ NSFileManager *manager = [NSFileManager defaultManager];
+ NSURL *supportURL = [manager URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:NULL];
+
+ if(supportURL != nil) {
+ NSURL *PcsxrAppSupport;
+ NSURL *MemCardPath;
+ NSURL *url;
+ BOOL dir;
+
+ PcsxrAppSupport = [supportURL URLByAppendingPathComponent:@"Pcsxr"];
+
+ // create them if needed
+ url = [PcsxrAppSupport URLByAppendingPathComponent:@"Bios"];
+ if (![url checkResourceIsReachableAndReturnError:NULL])
+ [manager createDirectoryAtURL:url withIntermediateDirectories:YES attributes:nil error:NULL];
+
+ MemCardPath = [PcsxrAppSupport URLByAppendingPathComponent:@"Memory Cards"];
+ url = MemCardPath;
+ if (![url checkResourceIsReachableAndReturnError:NULL])
+ [manager createDirectoryAtURL:url withIntermediateDirectories:YES attributes:nil error:NULL];
+
+ url = [PcsxrAppSupport URLByAppendingPathComponent:@"Patches"];
+ if (![url checkResourceIsReachableAndReturnError:NULL])
+ [manager createDirectoryAtURL:url withIntermediateDirectories:YES attributes:nil error:NULL];
+
+ url = [PcsxrAppSupport URLByAppendingPathComponent:@"PlugIns"];
+ if (![url checkResourceIsReachableAndReturnError:NULL])
+ [manager createDirectoryAtURL:url withIntermediateDirectories:YES attributes:nil error:NULL];
+
+ saveStatePath = [[[PcsxrAppSupport URLByAppendingPathComponent:@"Save States"] path] copy];
+ if (![manager fileExistsAtPath:saveStatePath isDirectory:&dir])
+ [manager createDirectoryAtPath:saveStatePath withIntermediateDirectories:YES attributes:nil error:NULL];
+
+ url = [MemCardPath URLByAppendingPathComponent:@"Mcd001.mcr"];
+ str = [[url path] fileSystemRepresentation];
+ if (str != nil)
+ strlcpy(Config.Mcd1, str, MAXPATHLEN);
+
+ url = [MemCardPath URLByAppendingPathComponent:@"Mcd002.mcr"];
+ str = [[url path] fileSystemRepresentation];
+ if (str != nil)
+ strlcpy(Config.Mcd2, str, MAXPATHLEN);
+
+ url = [PcsxrAppSupport URLByAppendingPathComponent:@"Bios"];
+ str = [[url path] fileSystemRepresentation];
+ if (str != nil)
+ strlcpy(Config.BiosDir, str, MAXPATHLEN);
+
+ url = [PcsxrAppSupport URLByAppendingPathComponent:@"Patches"];
+ str = [[url path] fileSystemRepresentation];
+ if (str != nil) {
+ strlcpy(Config.PatchesDir, str, MAXPATHLEN);
+ }
+ } else {
+ strcpy(Config.BiosDir, "Bios/");
+ strcpy(Config.PatchesDir, "Patches/");
+
+ //NSString constants don't need to be retained/released. In fact, retain/releasing them does nothing.
+ saveStatePath = @"sstates";
+ }
+
+ // set plugin path
+ path = [[NSBundle mainBundle] builtInPlugInsPath];
+ str = [path fileSystemRepresentation];
+ if (str != nil)
+ strlcpy(Config.PluginsDir, str, MAXPATHLEN);
+
+ // locate a bios
+ biosList = [[NSMutableArray alloc] init];
+
+ NSString *biosDir = [manager stringWithFileSystemRepresentation:Config.BiosDir length:strlen(Config.BiosDir)];
+ NSArray *bioses = [manager contentsOfDirectoryAtPath:biosDir error:NULL];
+ if (bioses) {
+ for (NSString *file in bioses) {
+ NSDictionary *attrib = [manager attributesOfItemAtPath:[[biosDir stringByAppendingPathComponent:file] stringByResolvingSymlinksInPath] error:NULL];
+
+ if ([[attrib fileType] isEqualToString:NSFileTypeRegular]) {
+ unsigned long long size = [attrib fileSize];
+ if ((size % (256 * 1024)) == 0 && size > 0) {
+ [biosList addObject:file];
+ }
+ }
+ }
+ }
+
+ [PcsxrController setConfigFromDefaults];
+}
+
++ (NSString*)saveStatePath:(int)slot
+{
+ if(slot >= 0) {
+ return [saveStatePath stringByAppendingPathComponent:[NSString stringWithFormat:@"%s-%3.3d.pcsxrstate", CdromId, slot]];
+ }
+
+ return saveStatePath;
+}
+
+- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
+{
+ NSFileManager *fm = [NSFileManager defaultManager];
+ NSWorkspace *workspace = [NSWorkspace sharedWorkspace];
+ if (skipFiles && [skipFiles count]) {
+ for (NSString *parsedFile in skipFiles) {
+ if ([filename isEqualToString:parsedFile]) {
+ return YES;
+ }
+ }
+ }
+
+ if (![fm fileExistsAtPath:filename]) {
+ NSLog(@"Nonexistant file %@ was passed to open.", filename );
+ return NO;
+ }
+
+ if ([[filename pathExtension] compare:@"bin" options:(NSCaseInsensitiveSearch | NSWidthInsensitiveSearch)]) {
+ NSDictionary *attrib = [fm attributesOfItemAtPath:filename error:NULL];
+ if ([[attrib fileType] isEqualToString:NSFileTypeRegular] && ([attrib fileSize] % (256 * 1024)) == 0 && [attrib fileSize] > 0 ) {
+ NSAlert *biosInfo = [NSAlert alertWithMessageText:NSLocalizedString(@"PlayStation BIOS File", @"PSX BIOS File") defaultButton:NSLocalizedString(@"BIOS_Copy", @"copy the BIOS over") alternateButton:NSLocalizedString(@"Cancel", @"Cancel") otherButton:NSLocalizedString(@"BIOS_Move", @"Move the bios over") informativeTextWithFormat:NSLocalizedString(@"The file \"%@\" seems to be a BIOS file. Do you want PCSX-R to copy it to the proper location?", @"Can we copy the BIOS?")];
+ biosInfo.alertStyle = NSInformationalAlertStyle;
+ switch ([biosInfo runModal]) {
+ case NSAlertFirstButtonReturn:
+ case NSAlertDefaultReturn:
+ {
+ NSError *theErr = nil;
+ NSURL *biosDirPath = [NSURL fileURLWithPath:[fm stringWithFileSystemRepresentation:Config.BiosDir length:strlen(Config.BiosDir)] isDirectory:YES];
+ NSURL *biosPath = [biosDirPath URLByAppendingPathComponent:[filename lastPathComponent]];
+ if ([biosPath checkResourceIsReachableAndReturnError:NULL]) {
+ NSAlert *alreadyThere = [NSAlert alertWithMessageText:NSLocalizedString(@"BIOS Already Exists", @"BIOS file already there.") defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:NSLocalizedString(@"There already exists a BIOS file at \"%1$@\": not copying the file at \"%2$@\".\n\nIf you do want to use the BIOS file at \"%2$@\", delete the BIOS at \"%1$@\".", @"What to do"), [biosPath path], filename];
+ alreadyThere.alertStyle = NSCriticalAlertStyle;
+ [alreadyThere runModal];
+ return NO;
+ }
+ if (![fm copyItemAtURL:[NSURL fileURLWithPath:filename isDirectory:NO] toURL:biosPath error:&theErr]) {
+ [[NSAlert alertWithError:theErr] runModal];
+ return NO;
+ }
+ }
+ break;
+
+ case NSAlertThirdButtonReturn:
+ case NSAlertOtherReturn:
+ {
+ NSError *theErr = nil;
+ NSURL *biosDirPath = [NSURL fileURLWithPath:[fm stringWithFileSystemRepresentation:Config.BiosDir length:strlen(Config.BiosDir)] isDirectory:YES];
+ NSURL *biosPath = [biosDirPath URLByAppendingPathComponent:[filename lastPathComponent]];
+ if ([biosPath checkResourceIsReachableAndReturnError:NULL]) {
+ NSAlert *alreadyThere = [NSAlert alertWithMessageText:NSLocalizedString(@"BIOS Already Exists", @"BIOS file already there.") defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:NSLocalizedString(@"There already exists a BIOS file at \"%1$@\": not moving the file at \"%2$@\".\n\nIf you do want to use the BIOS file at \"%2$@\", delete the BIOS at \"%1$@\".", @"What to do"), [biosPath path], filename];
+ alreadyThere.alertStyle = NSCriticalAlertStyle;
+ [alreadyThere runModal];
+ return NO;
+ }
+ if (![fm moveItemAtURL:[NSURL fileURLWithPath:filename isDirectory:NO] toURL:biosPath error:&theErr]) {
+ [[NSAlert alertWithError:theErr] runModal];
+ return NO;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ return YES;
+ }
+ }
+
+ NSError *err = nil;
+ NSString *utiFile = [workspace typeOfFile:filename error:&err];
+ if (err) {
+ NSRunAlertPanel(NSLocalizedString(@"Error opening file", nil), NSLocalizedString(@"Unable to open %@: %@", nil), nil, nil, nil, [filename lastPathComponent], err);
+ return NO;
+ }
+ static NSArray *handlers = nil;
+ if (handlers == nil) {
+ handlers = @[[PcsxrPluginHandler class], [PcsxrMemCardHandler class], [PcsxrFreezeStateHandler class], [PcsxrDiscHandler class], [PcsxrCheatHandler class]];
+ }
+ BOOL isHandled = NO;
+ for (Class fileHandler in handlers) {
+ NSObject<PcsxrFileHandle> *hand = [[fileHandler alloc] init];
+ BOOL canHandle = NO;
+ for (NSString *uti in [fileHandler supportedUTIs]) {
+ if ([workspace type:utiFile conformsToType:uti]) {
+ canHandle = YES;
+ break;
+ }
+ }
+ if (canHandle) {
+ isHandled = [hand handleFile:filename];
+ break;
+ }
+ }
+
+ return isHandled;
+}
+
+@end