pcsxr-1.9.92
[pcsx_rearmed.git] / macosx / PcsxController.m
1 #import <Cocoa/Cocoa.h>
2 #import "PcsxController.h"
3 #import "ConfigurationController.h"
4 #import "EmuThread.h"
5 #include "psxcommon.h"
6 #include "plugins.h"
7 #include "misc.h"
8 #include "ExtendedKeys.h"
9
10 NSDictionary *prefStringKeys;
11 NSDictionary *prefByteKeys;
12 NSMutableArray *biosList;
13 NSString *saveStatePath;
14
15 @implementation PcsxController
16
17 - (IBAction)ejectCD:(id)sender
18 {
19         NSMutableString *deviceName;
20         NSTask *ejectTask;
21         NSRange rdiskRange;
22
23         BOOL wasPaused = [EmuThread pauseSafe];
24
25         /* close connection to current cd */
26         if ([EmuThread active])
27                 CDR_close();
28
29         // switch to another ISO if using internal image reader, otherwise eject the CD
30         if (UsingIso()) {
31                 NSOpenPanel* openDlg = [NSOpenPanel openPanel];
32
33                 [openDlg setCanChooseFiles:YES];
34                 [openDlg setCanChooseDirectories:NO];
35
36                 if ([openDlg runModal] == NSOKButton) {
37                         NSArray* files = [openDlg filenames];
38                         SetCdOpenCaseTime(time(NULL) + 2);
39                         SetIsoFile((const char *)[[files objectAtIndex:0] fileSystemRepresentation]);
40                 }
41         } else {
42                 if (CDR_getDriveLetter() != nil) {
43                         deviceName = [NSMutableString stringWithCString:CDR_getDriveLetter()];
44
45                         // delete the 'r' in 'rdisk'
46                         rdiskRange = [deviceName rangeOfString:@"rdisk"];
47                         if (rdiskRange.length != 0) {
48                                 rdiskRange.length = 1;
49                                 [deviceName deleteCharactersInRange:rdiskRange];
50                         }
51                         // execute hdiutil to eject the device
52                         ejectTask = [NSTask launchedTaskWithLaunchPath:@"/usr/bin/hdiutil" arguments:[NSArray arrayWithObjects:@"eject", deviceName, nil]];
53                         [ejectTask waitUntilExit];
54                 }
55         }
56
57         /* and open new cd */
58         if ([EmuThread active])
59                 CDR_open();
60
61         if (!wasPaused) {
62                 [EmuThread resume];
63         }
64 }
65
66 - (IBAction)pause:(id)sender
67 {
68     if ([EmuThread isPaused]) {
69         //[sender setState:NSOffState];
70         [EmuThread resume];
71     }
72     else {
73         //[sender setState:NSOnState];
74         [EmuThread pause];
75     }
76 }
77
78 - (IBAction)preferences:(id)sender
79 {
80         /* load the nib if it hasn't yet */
81         if (preferenceWindow == nil) {
82                 if (preferencesController == nil) {
83                         preferencesController = [[ConfigurationController alloc] initWithWindowNibName:@"Configuration"];
84                 }
85                 preferenceWindow = [preferencesController window];
86         }
87
88         /* show the window */
89         [preferenceWindow makeKeyAndOrderFront:self];
90         [preferencesController showWindow:self];
91 }
92
93 - (IBAction)reset:(id)sender
94 {
95     [EmuThread reset];
96 }
97
98 - (IBAction)runCD:(id)sender
99 {
100         SetIsoFile(NULL);
101         [EmuThread run];
102 }
103
104 - (IBAction)runIso:(id)sender
105 {
106         NSOpenPanel* openDlg = [NSOpenPanel openPanel];
107
108         [openDlg setCanChooseFiles:YES];
109         [openDlg setCanChooseDirectories:NO];
110
111         if ([openDlg runModalForDirectory:nil file:nil] == NSOKButton) {
112                 NSArray* files = [openDlg filenames];
113                 SetIsoFile((const char *)[[files objectAtIndex:0] fileSystemRepresentation]);
114                 [EmuThread run];
115     }
116 }
117
118 - (IBAction)runBios:(id)sender
119 {
120         SetIsoFile(NULL);
121         [EmuThread runBios];
122 }
123
124 - (IBAction)freeze:(id)sender
125 {
126         int num = [sender tag];
127         NSString *path = [NSString stringWithFormat:@"%@/%s-%3.3d.pcsxstate", saveStatePath, CdromId, num];
128
129         [EmuThread freezeAt:path which:num-1];
130 }
131
132 - (IBAction)defrost:(id)sender
133 {
134         NSString *path = [NSString stringWithFormat:@"%@/%s-%3.3d.pcsxstate", saveStatePath, CdromId, [sender tag]];
135         [EmuThread defrostAt:path];
136 }
137
138 - (IBAction)fullscreen:(id)sender
139 {
140         GPU_keypressed(GPU_FULLSCREEN_KEY);
141 }
142
143 - (BOOL)validateMenuItem:(id <NSMenuItem>)menuItem
144 {
145         if ([menuItem action] == @selector(pause:)) {
146                 [menuItem setState:([EmuThread isPaused] ? NSOnState : NSOffState)];
147         }
148
149         if ([menuItem action] == @selector(pause:) || [menuItem action] == @selector(fullscreen:))
150                 return [EmuThread active];
151
152         if ([menuItem action] == @selector(reset:) || [menuItem action] == @selector(ejectCD:) ||
153                  [menuItem action] == @selector(freeze:))
154                 return [EmuThread active] && ![EmuThread isRunBios];
155
156         if ([menuItem action] == @selector(runCD:) || [menuItem action] == @selector(runIso:) ||
157                  [menuItem action] == @selector(runBios:)) {
158                 if (preferenceWindow != nil)
159                         if ([preferenceWindow isVisible])
160                                 return NO;
161
162                 if ([menuItem action] == @selector(runBios:) && strcmp(Config.Bios, "HLE") == 0)
163                         return NO;
164
165                 return ![EmuThread active];
166         }
167
168         if ([menuItem action] == @selector(defrost:)) {
169                 if (![EmuThread active] || [EmuThread isRunBios])
170                         return NO;
171
172                 NSString *path = [NSString stringWithFormat:@"%@/%s-%3.3d.pcsxstate", saveStatePath, CdromId, [menuItem tag]];
173                 return (CheckState((char *)[path fileSystemRepresentation]) == 0);
174         }
175
176         if ([menuItem action] == @selector(preferences:))
177                 return ![EmuThread active];
178
179         return YES;
180 }
181
182 - (void)applicationWillResignActive:(NSNotification *)aNotification
183 {
184         wasPausedBeforeBGSwitch = [EmuThread isPaused];
185
186         if (sleepInBackground) {
187                  [EmuThread pause];
188         }
189 }
190
191 - (void)applicationDidBecomeActive:(NSNotification *)aNotification
192 {
193         if (sleepInBackground && !wasPausedBeforeBGSwitch) {
194                 [EmuThread resume];
195         }
196 }
197
198 - (void)awakeFromNib
199 {
200         pluginList = [[PluginList alloc] init];
201         if (![pluginList configured] /*!Config.Gpu[0] || !Config.Spu[0] || !Config.Pad1[0] || !Config.Cdr[0]*/) {
202                 // configure plugins
203                 [self preferences:nil];
204
205                 NSRunCriticalAlertPanel(NSLocalizedString(@"Missing plugins!", nil),
206                                 NSLocalizedString(@"Pcsx is missing one or more critical plugins. You will need to install these in order to play games.", nil), 
207                                 nil, nil, nil);
208         }
209
210         if (![PcsxController biosAvailable]) {
211                 NSRunInformationalAlertPanel(NSLocalizedString(@"Missing BIOS!", nil),
212                                 NSLocalizedString(@"Pcsx 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.\n"
213                                                                                 @"If you have a BIOS available, please copy it to\n~/Library/Application Support/Pcsx/Bios/", nil), 
214                                 nil, nil, nil);
215         }
216
217         sleepInBackground = YES;
218 }
219
220 - (void)dealloc
221 {
222         [pluginList release];
223         [super dealloc];
224 }
225
226 + (void)setConfigFromDefaults
227 {
228         NSEnumerator *enumerator;
229         const char *str;
230         NSString *key;
231         NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
232
233         /*
234         enumerator = [prefStringKeys keyEnumerator];
235         while ((key = [enumerator nextObject])) {
236                 str = [[defaults stringForKey:key] fileSystemRepresentation];
237                 char *dst = (char *)[[prefStringKeys objectForKey:key] pointerValue];
238                 if (str != nil && dst != nil) strncpy(dst, str, 255);
239         }*/
240
241         enumerator = [prefByteKeys keyEnumerator];
242         while ((key = [enumerator nextObject])) {
243                 u8 *dst = (u8 *)[[prefByteKeys objectForKey:key] pointerValue];
244                 if (dst != nil) *dst = [defaults integerForKey:key];
245         }
246
247         // special cases
248         //str = [[defaults stringForKey:@"PluginPAD"] fileSystemRepresentation];
249         //if (str != nil) strncpy(Config.Pad2, str, 255);
250
251         str = [[defaults stringForKey:@"Bios"] fileSystemRepresentation];
252         if (str) {
253                 NSString *path = [defaults stringForKey:@"Bios"];
254                 int index = [biosList indexOfObject:path];
255
256                 if (-1 == index) {
257                         [biosList insertObject:path atIndex:0];
258                 } else if (0 < index) {
259                         [biosList exchangeObjectAtIndex:index withObjectAtIndex:0];
260                 }
261         }
262
263         str = [[defaults stringForKey:@"Mcd1"] fileSystemRepresentation];
264         if (str) strncpy(Config.Mcd1, str, MAXPATHLEN);
265
266         str = [[defaults stringForKey:@"Mcd2"] fileSystemRepresentation];
267         if (str) strncpy(Config.Mcd2, str, MAXPATHLEN);
268
269         if ([defaults boolForKey:@"UseHLE"] || 0 == [biosList count]) {
270                 strcpy(Config.Bios, "HLE");
271         } else {
272                 str = [(NSString *)[biosList objectAtIndex:0] fileSystemRepresentation];
273                 if (str != nil) strncpy(Config.Bios, str, MAXPATHLEN);
274                 else strcpy(Config.Bios, "HLE");
275         }
276
277         // FIXME: hack
278         strcpy(Config.Net, "Disabled");
279 }
280
281 + (void)setDefaultFromConfig:(NSString *)defaultKey
282 {
283         NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
284
285         char *str = (char *)[[prefStringKeys objectForKey:defaultKey] pointerValue];
286         if (str) {
287                 [defaults setObject:[NSString stringWithCString:str] forKey:defaultKey];
288                 return;
289         }
290
291         u8 *val = (u8 *)[[prefByteKeys objectForKey:defaultKey] pointerValue];
292         if (val) {
293                 [defaults setInteger:*val forKey:defaultKey];
294                 return;
295         }
296 }
297
298 + (BOOL)biosAvailable
299 {
300         return ([biosList count] > 0);
301 }
302
303 // called when class is initialized
304 + (void)initialize
305 {
306         NSString *path;
307         const char *str;
308         NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
309         NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
310                 @"Disabled", @"PluginNET",
311                 [NSNumber numberWithInt:1], @"NoDynarec",
312                 [NSNumber numberWithInt:1], @"AutoDetectVideoType",
313                 [NSNumber numberWithInt:0], @"UseHLE",
314                 nil];
315
316         [defaults registerDefaults:appDefaults];
317
318         prefStringKeys = [[NSDictionary alloc] initWithObjectsAndKeys:
319                 [NSValue valueWithPointer:Config.Gpu], @"PluginGPU",
320                 [NSValue valueWithPointer:Config.Spu], @"PluginSPU",
321                 [NSValue valueWithPointer:Config.Pad1], @"PluginPAD",
322                 [NSValue valueWithPointer:Config.Cdr], @"PluginCDR",
323                 [NSValue valueWithPointer:Config.Net], @"PluginNET",
324                 [NSValue valueWithPointer:Config.Mcd1], @"Mcd1",
325                 [NSValue valueWithPointer:Config.Mcd2], @"Mcd2",
326                 nil];
327
328         prefByteKeys = [[NSDictionary alloc] initWithObjectsAndKeys:
329                 [NSValue valueWithPointer:&Config.Xa], @"NoXaAudio",
330                 [NSValue valueWithPointer:&Config.Sio], @"SioIrqAlways",
331                 [NSValue valueWithPointer:&Config.Mdec], @"BlackAndWhiteMDECVideo",
332                 [NSValue valueWithPointer:&Config.PsxAuto], @"AutoDetectVideoType",
333                 [NSValue valueWithPointer:&Config.PsxType], @"VideoTypePAL",
334                 [NSValue valueWithPointer:&Config.Cdda], @"NoCDAudio",
335                 [NSValue valueWithPointer:&Config.Cpu], @"NoDynarec",
336                 [NSValue valueWithPointer:&Config.PsxOut], @"ConsoleOutput",
337                 [NSValue valueWithPointer:&Config.SpuIrq], @"SpuIrqAlways",
338                 [NSValue valueWithPointer:&Config.RCntFix], @"RootCounterFix",
339                 [NSValue valueWithPointer:&Config.VSyncWA], @"VideoSyncWAFix",
340                 nil];
341
342         // setup application support paths
343         NSArray *libPaths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
344         if ([libPaths count] > 0) {
345                 NSString *path;
346                 BOOL dir;
347
348                 // create them if needed
349                 NSFileManager *dfm = [NSFileManager defaultManager];
350                 NSString *supportPath = [NSString stringWithFormat:@"%@/Application Support", [libPaths objectAtIndex:0]];
351                 if (![dfm fileExistsAtPath:supportPath isDirectory:&dir])
352                         [dfm createDirectoryAtPath:supportPath attributes:nil];
353
354                 path = [NSString stringWithFormat:@"%@/Pcsx", supportPath];
355                 if (![dfm fileExistsAtPath:path isDirectory:&dir])
356                         [dfm createDirectoryAtPath:path attributes:nil];
357
358                 path = [NSString stringWithFormat:@"%@/Pcsx/Bios", supportPath];
359                 if (![dfm fileExistsAtPath:path isDirectory:&dir])
360                         [dfm createDirectoryAtPath:path attributes:nil];
361
362                 path = [NSString stringWithFormat:@"%@/Pcsx/Memory Cards", supportPath];
363                 if (![dfm fileExistsAtPath:path isDirectory:&dir])
364                         [dfm createDirectoryAtPath:path attributes:nil];
365
366                 path = [NSString stringWithFormat:@"%@/Pcsx/Patches", supportPath];
367                 if (![dfm fileExistsAtPath:path isDirectory:&dir])
368                         [dfm createDirectoryAtPath:path attributes:nil];
369
370                 saveStatePath = [[NSString stringWithFormat:@"%@/Pcsx/Save States", supportPath] retain];
371                 if (![dfm fileExistsAtPath:saveStatePath isDirectory:&dir])
372                         [dfm createDirectoryAtPath:saveStatePath attributes:nil];
373
374                 path = [NSString stringWithFormat:@"%@/Pcsx/Memory Cards/Mcd001.mcr", supportPath];
375                 str = [path fileSystemRepresentation];
376                 if (str != nil) strncpy(Config.Mcd1, str, 255);
377
378                 path = [NSString stringWithFormat:@"%@/Pcsx/Memory Cards/Mcd002.mcr", supportPath];
379                 str = [path fileSystemRepresentation];
380                 if (str != nil) strncpy(Config.Mcd2, str, 255);
381
382                 path = [NSString stringWithFormat:@"%@/Pcsx/Bios/", supportPath];
383                 str = [path fileSystemRepresentation];
384                 if (str != nil) strncpy(Config.BiosDir, str, 255);
385
386                 path = [NSString stringWithFormat:@"%@/Pcsx/Patches/", supportPath];
387                 str = [path fileSystemRepresentation];
388                 if (str != nil) strncpy(Config.PatchesDir, str, 255);
389         } else {
390                 strcpy(Config.BiosDir, "Bios/");
391                 strcpy(Config.PatchesDir, "Patches/");
392
393                 saveStatePath = @"sstates";
394                 [saveStatePath retain];
395         }
396
397         // set plugin path
398         path = [[[NSBundle mainBundle] builtInPlugInsPath] stringByAppendingString:@"/"];
399         str = [path fileSystemRepresentation];
400         if (str != nil) strncpy(Config.PluginsDir, str, 255);
401
402         // locate a bios
403         biosList = [[NSMutableArray alloc] init];
404         NSFileManager *manager = [NSFileManager defaultManager];
405         NSArray *bioses = [manager directoryContentsAtPath:[NSString stringWithCString:Config.BiosDir]];
406         if (bioses) {
407                 int i;
408                 for (i = 0; i < [bioses count]; i++) {
409                         NSString *file = [bioses objectAtIndex:i];
410                         NSDictionary *attrib = [manager fileAttributesAtPath:[NSString stringWithFormat:@"%s%@", Config.BiosDir, file] traverseLink:YES];
411
412                         if ([[attrib fileType] isEqualToString:NSFileTypeRegular]) {
413                                 unsigned long long size = [attrib fileSize];
414                                 if (([attrib fileSize] % (256 * 1024)) == 0 && size > 0) {
415                                         [biosList addObject:file];
416                                 }
417                         }
418                 }
419         }
420
421         [PcsxController setConfigFromDefaults];
422 }
423
424
425 @end