|
|
1.1 ! root 1: /* SDLMain.m - main entry point for our Cocoa-ized SDL app ! 2: Initial Version: Darrell Walisser <[email protected]> ! 3: Non-NIB-Code & other changes: Max Horn <[email protected]> ! 4: ! 5: Feb-Mar 2006, S�bastien Molines - Added prefs & create floppy ! 6: June 2006, S�bastien Molines - Added capture and memory snapshot ! 7: ! 8: Feel free to customize this file to suit your needs ! 9: */ ! 10: ! 11: #import "SDL.h" ! 12: #import "SDLMain.h" ! 13: #import "SDL_events.h" ! 14: #import "Shared.h" ! 15: #import <sys/param.h> /* for MAXPATHLEN */ ! 16: #import <unistd.h> ! 17: ! 18: #include "dialog.h" ! 19: #include "floppy.h" ! 20: #include "reset.h" ! 21: #include "screenSnapShot.h" ! 22: #include "memorySnapShot.h" ! 23: #include "sound.h" ! 24: ! 25: static int gArgc; ! 26: static char **gArgv; ! 27: static BOOL gFinderLaunch; ! 28: ! 29: @interface SDLApplication : NSApplication ! 30: @end ! 31: ! 32: @implementation SDLApplication ! 33: /* Invoked from the Quit menu item */ ! 34: - (void)terminate:(id)sender ! 35: { ! 36: /* Post a SDL_QUIT event */ ! 37: SDL_Event event; ! 38: event.type = SDL_QUIT; ! 39: SDL_PushEvent(&event); ! 40: } ! 41: @end ! 42: ! 43: ! 44: /* The main class of the application, the application's delegate */ ! 45: @implementation SDLMain ! 46: ! 47: - (IBAction)prefsMenu:(id)sender ! 48: { ! 49: static int in_propdialog = 0; ! 50: ! 51: if (in_propdialog) ! 52: return; ! 53: ++in_propdialog; ! 54: Dialog_DoProperty(); ! 55: --in_propdialog; ! 56: } ! 57: ! 58: - (IBAction)warmReset:(id)sender ! 59: { ! 60: int b; ! 61: ! 62: b = NSRunAlertPanel (@"Warm reset!", ! 63: @"Really reset the emulator? All current work will be lost. Click Cancel to continue without reset.", ! 64: @"OK", @"Cancel", nil); ! 65: //printf("b=%i\n",b); ! 66: if (b == 1) ! 67: Reset_Warm(); ! 68: } ! 69: ! 70: - (IBAction)coldReset:(id)sender ! 71: { ! 72: int b; ! 73: ! 74: b = NSRunAlertPanel (@"Cold reset!", ! 75: @"Really reset the emulator? All current work will be lost. Click Cancel to continue without reset.", ! 76: @"OK", @"Cancel", nil); ! 77: //printf("b=%i\n",b); ! 78: if (b == 1) ! 79: Reset_Cold(); ! 80: } ! 81: ! 82: - (IBAction)insertDiskA:(id)sender ! 83: { ! 84: NSString *path = nil; ! 85: NSOpenPanel *openPanel = [ NSOpenPanel openPanel ]; ! 86: ! 87: if ( [ openPanel runModalForDirectory:nil ! 88: file:@"SavedGame" types:nil ] ) { ! 89: ! 90: path = [ [ openPanel filenames ] objectAtIndex:0 ]; ! 91: } ! 92: ! 93: if (path != nil) ! 94: { ! 95: // Make a non-const C string out of it ! 96: const char* constSzPath = [path cString]; ! 97: size_t cbPath = strlen(constSzPath) + 1; ! 98: char szPath[cbPath]; ! 99: strncpy(szPath, constSzPath, cbPath); ! 100: ! 101: Floppy_InsertDiskIntoDrive(0, szPath); ! 102: } ! 103: } ! 104: ! 105: - (IBAction)insertDiskB:(id)sender ! 106: { ! 107: NSString *path = nil; ! 108: NSOpenPanel *openPanel = [ NSOpenPanel openPanel ]; ! 109: ! 110: if ( [ openPanel runModalForDirectory:nil ! 111: file:@"SavedGame" types:nil ] ) { ! 112: ! 113: path = [ [ openPanel filenames ] objectAtIndex:0 ]; ! 114: } ! 115: ! 116: if (path != nil) ! 117: { ! 118: // Make a non-const C string out of it ! 119: const char* constSzPath = [path cString]; ! 120: size_t cbPath = strlen(constSzPath) + 1; ! 121: char szPath[cbPath]; ! 122: strncpy(szPath, constSzPath, cbPath); ! 123: ! 124: Floppy_InsertDiskIntoDrive(1, szPath); ! 125: } ! 126: } ! 127: ! 128: /*-----------------------------------------------------------------------*/ ! 129: /* ! 130: Controls the enabled state of the menu items ! 131: */ ! 132: - (BOOL)validateMenuItem:(NSMenuItem*)item ! 133: { ! 134: if (item == beginCaptureAnim) ! 135: { ! 136: return !ScreenSnapShot_AreWeRecording(); ! 137: } ! 138: if (item == endCaptureAnim) ! 139: { ! 140: return ScreenSnapShot_AreWeRecording(); ! 141: } ! 142: if (item == beginCaptureSound) ! 143: { ! 144: return !Sound_AreWeRecording(); ! 145: } ! 146: if (item == endCaptureSound) ! 147: { ! 148: return Sound_AreWeRecording(); ! 149: } ! 150: ! 151: return YES; ! 152: } ! 153: ! 154: - (IBAction)captureScreen:(id)sender ! 155: { ! 156: GuiOsx_PauseAndSwitchToCocoaUI(); ! 157: ScreenSnapShot_SaveScreen(); ! 158: GuiOsx_ResumeFromCocoaUI(); ! 159: } ! 160: ! 161: - (IBAction)captureAnimation:(id)sender ! 162: { ! 163: GuiOsx_PauseAndSwitchToCocoaUI(); ! 164: ScreenSnapShot_BeginRecording(DialogParams.Screen.bCaptureChange, 25); ! 165: GuiOsx_ResumeFromCocoaUI(); ! 166: } ! 167: ! 168: - (IBAction)endCaptureAnimation:(id)sender ! 169: { ! 170: GuiOsx_PauseAndSwitchToCocoaUI(); ! 171: ScreenSnapShot_EndRecording(); ! 172: GuiOsx_ResumeFromCocoaUI(); ! 173: } ! 174: ! 175: - (IBAction)captureSound:(id)sender ! 176: { ! 177: GuiOsx_PauseAndSwitchToCocoaUI(); ! 178: ! 179: // Get the path from the user settings ! 180: NSString *preferredPath = [[NSString stringWithCString:(ConfigureParams.Sound.szYMCaptureFileName)] stringByAbbreviatingWithTildeInPath]; ! 181: ! 182: // Determine the directory and filename ! 183: NSString *directoryToOpen; ! 184: NSString *fileToPreselect; ! 185: if ((preferredPath != nil) && ([preferredPath length] > 0)) ! 186: { ! 187: // There is existing path: we will open its directory with its file pre-selected. ! 188: directoryToOpen = [preferredPath stringByDeletingLastPathComponent]; ! 189: fileToPreselect = [preferredPath lastPathComponent]; ! 190: } ! 191: else ! 192: { ! 193: // Currently no path: we will open the user's directory with no file selected. ! 194: directoryToOpen = [@"~" stringByExpandingTildeInPath]; ! 195: fileToPreselect = @"hatari.wav"; ! 196: } ! 197: ! 198: // Create and configure a SavePanel for choosing what file to write ! 199: NSSavePanel *savePanel = [NSSavePanel savePanel]; ! 200: [savePanel setAllowedFileTypes:[NSArray arrayWithObjects:@"ym", @"wav", nil]]; ! 201: [savePanel setExtensionHidden:NO]; ! 202: [savePanel setMessage:@"Please specify an .ym or a .wav file."]; // TODO: Move to localizable resources ! 203: ! 204: // Run the SavePanel, then check if the user clicked OK and selected at least one file ! 205: if (NSFileHandlingPanelOKButton == [savePanel runModalForDirectory:directoryToOpen file:fileToPreselect] ) ! 206: { ! 207: // Get the path to the selected file ! 208: NSString *path = [savePanel filename]; ! 209: ! 210: // Store the path in the user settings ! 211: GuiOsx_ExportPathString(path, ConfigureParams.Sound.szYMCaptureFileName, sizeof(ConfigureParams.Sound.szYMCaptureFileName)); ! 212: ! 213: // Begin capture ! 214: Sound_BeginRecording(ConfigureParams.Sound.szYMCaptureFileName); ! 215: } ! 216: ! 217: GuiOsx_ResumeFromCocoaUI(); ! 218: } ! 219: ! 220: - (IBAction)endCaptureSound:(id)sender ! 221: { ! 222: GuiOsx_PauseAndSwitchToCocoaUI(); ! 223: Sound_EndRecording(); ! 224: GuiOsx_ResumeFromCocoaUI(); ! 225: } ! 226: ! 227: - (IBAction)saveMemorySnap:(id)sender ! 228: { ! 229: GuiOsx_PauseAndSwitchToCocoaUI(); ! 230: ! 231: // Get the path from the user settings ! 232: NSString *preferredPath = [[NSString stringWithCString:(ConfigureParams.Memory.szMemoryCaptureFileName)] stringByAbbreviatingWithTildeInPath]; ! 233: ! 234: // Determine the directory and filename ! 235: NSString *directoryToOpen; ! 236: NSString *fileToPreselect; ! 237: if ((preferredPath != nil) && ([preferredPath length] > 0)) ! 238: { ! 239: // There is existing path: we will open its directory with its file pre-selected. ! 240: directoryToOpen = [preferredPath stringByDeletingLastPathComponent]; ! 241: fileToPreselect = [preferredPath lastPathComponent]; ! 242: } ! 243: else ! 244: { ! 245: // Currently no path: we will open the user's directory with the default filename. ! 246: directoryToOpen = [@"~" stringByExpandingTildeInPath]; ! 247: fileToPreselect = @"hatari.sav"; ! 248: } ! 249: ! 250: // Create and configure a SavePanel for choosing what file to write ! 251: NSSavePanel *savePanel = [NSSavePanel savePanel]; ! 252: [savePanel setExtensionHidden:NO]; ! 253: ! 254: // Run the SavePanel, then check if the user clicked OK and selected at least one file ! 255: if (NSFileHandlingPanelOKButton == [savePanel runModalForDirectory:directoryToOpen file:fileToPreselect] ) ! 256: { ! 257: // Get the path to the selected file ! 258: NSString *path = [savePanel filename]; ! 259: ! 260: // Store the path in the user settings ! 261: GuiOsx_ExportPathString(path, ConfigureParams.Memory.szMemoryCaptureFileName, sizeof(ConfigureParams.Memory.szMemoryCaptureFileName)); ! 262: ! 263: // Perform the memory snapshot save ! 264: MemorySnapShot_Capture(ConfigureParams.Memory.szMemoryCaptureFileName); ! 265: } ! 266: ! 267: GuiOsx_ResumeFromCocoaUI(); ! 268: } ! 269: ! 270: - (IBAction)restoreMemorySnap:(id)sender ! 271: { ! 272: GuiOsx_PauseAndSwitchToCocoaUI(); ! 273: ! 274: // Create and configure an OpenPanel ! 275: NSOpenPanel *openPanel = [NSOpenPanel openPanel]; ! 276: ! 277: // Get the path from the user settings ! 278: NSString *oldPath = [NSString stringWithCString:(ConfigureParams.Memory.szMemoryCaptureFileName)]; ! 279: ! 280: // Determine the directory and filename ! 281: NSString *directoryToOpen; ! 282: NSString *fileToPreselect; ! 283: if ((oldPath != nil) && ([oldPath length] > 0)) ! 284: { ! 285: // There is existing path: we will open its directory with its file pre-selected. ! 286: directoryToOpen = [oldPath stringByDeletingLastPathComponent]; ! 287: fileToPreselect = [oldPath lastPathComponent]; ! 288: } ! 289: else ! 290: { ! 291: // Currently no path: we will open the user's directory with no file selected. ! 292: directoryToOpen = [@"~" stringByExpandingTildeInPath]; ! 293: fileToPreselect = nil; ! 294: } ! 295: ! 296: // Run the OpenPanel, then check if the user clicked OK and selected at least one file ! 297: if ( (NSOKButton == [openPanel runModalForDirectory:directoryToOpen file:fileToPreselect types:nil] ) ! 298: && ([[openPanel filenames] count] > 0) ) ! 299: { ! 300: // Get the path to the selected file ! 301: NSString *path = [[openPanel filenames] objectAtIndex:0]; ! 302: ! 303: // Perform the memory snapshot load ! 304: MemorySnapShot_Restore([path cString]); ! 305: } ! 306: ! 307: GuiOsx_ResumeFromCocoaUI(); ! 308: } ! 309: ! 310: - (IBAction)doFullScreen:(id)sender ! 311: { ! 312: // A call to Screen_EnterFullScreen() would be required, but this causes a crash when using SDL runtime 1.2.11, probably due to conflicts between Cocoa and SDL. ! 313: // Therefore we simulate the fullscreen key press instead ! 314: ! 315: SDL_KeyboardEvent event; ! 316: event.type = SDL_KEYDOWN; ! 317: event.which = 0; ! 318: event.state = SDL_PRESSED; ! 319: event.keysym.sym = SDLK_F11; ! 320: SDL_PushEvent((SDL_Event*)&event); // Send the F11 key press ! 321: event.type = SDL_KEYUP; ! 322: event.state = SDL_RELEASED; ! 323: SDL_PushEvent((SDL_Event*)&event); // Send the F11 key release ! 324: } ! 325: ! 326: - (IBAction)help:(id)sender ! 327: { ! 328: [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://hatari.sourceforge.net/"]]; ! 329: /* ! 330: NSRunAlertPanel (@"Help", ! 331: @"Sorry, there is no built-in help available.\n\nPlease visit http://hatari.sourceforge.net/ for more information.\n\n", ! 332: @"OK", nil, nil); ! 333: */ ! 334: } ! 335: ! 336: ! 337: /* Set the working directory to the .app's parent directory */ ! 338: - (void) setupWorkingDirectory:(BOOL)shouldChdir ! 339: { ! 340: char parentdir[MAXPATHLEN]; ! 341: char *c; ! 342: ! 343: strncpy ( parentdir, gArgv[0], sizeof(parentdir) ); ! 344: c = (char*) parentdir; ! 345: ! 346: while (*c != '\0') /* go to end */ ! 347: c++; ! 348: ! 349: while (*c != '/') /* back up to parent */ ! 350: c--; ! 351: ! 352: *c++ = '\0'; /* cut off last part (binary name) */ ! 353: ! 354: if (shouldChdir) ! 355: { ! 356: assert ( chdir (parentdir) == 0 ); /* chdir to the binary app's parent */ ! 357: assert ( chdir ("../../../") == 0 ); /* chdir to the .app's parent */ ! 358: } ! 359: } ! 360: ! 361: ! 362: /* Called when the internal event loop has just started running */ ! 363: - (void) applicationDidFinishLaunching: (NSNotification *) note ! 364: { ! 365: int status; ! 366: ! 367: /* Set the working directory to the .app's parent directory */ ! 368: [self setupWorkingDirectory:gFinderLaunch]; ! 369: ! 370: /* Hand off to main application code */ ! 371: status = SDL_main (gArgc, gArgv); ! 372: ! 373: /* We're done, thank you for playing */ ! 374: exit(status); ! 375: } ! 376: ! 377: @end ! 378: ! 379: ! 380: @implementation NSString (ReplaceSubString) ! 381: ! 382: - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString ! 383: { ! 384: unsigned int bufferSize; ! 385: unsigned int selfLen = [self length]; ! 386: unsigned int aStringLen = [aString length]; ! 387: unichar *buffer; ! 388: NSRange localRange; ! 389: NSString *result; ! 390: ! 391: bufferSize = selfLen + aStringLen - aRange.length; ! 392: buffer = NSAllocateMemoryPages(bufferSize*sizeof(unichar)); ! 393: ! 394: /* Get first part into buffer */ ! 395: localRange.location = 0; ! 396: localRange.length = aRange.location; ! 397: [self getCharacters:buffer range:localRange]; ! 398: ! 399: /* Get middle part into buffer */ ! 400: localRange.location = 0; ! 401: localRange.length = aStringLen; ! 402: [aString getCharacters:(buffer+aRange.location) range:localRange]; ! 403: ! 404: /* Get last part into buffer */ ! 405: localRange.location = aRange.location + aRange.length; ! 406: localRange.length = selfLen - localRange.location; ! 407: [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange]; ! 408: ! 409: /* Build output string */ ! 410: result = [NSString stringWithCharacters:buffer length:bufferSize]; ! 411: ! 412: NSDeallocateMemoryPages(buffer, bufferSize); ! 413: ! 414: return result; ! 415: } ! 416: ! 417: @end ! 418: ! 419: ! 420: ! 421: #ifdef main ! 422: # undef main ! 423: #endif ! 424: ! 425: ! 426: /* Main entry point to executable - should *not* be SDL_main! */ ! 427: int main (int argc, char **argv) ! 428: { ! 429: ! 430: /* Copy the arguments into a global variable */ ! 431: int i; ! 432: ! 433: /* This is passed if we are launched by double-clicking */ ! 434: if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) { ! 435: gArgc = 1; ! 436: gFinderLaunch = YES; ! 437: } else { ! 438: gArgc = argc; ! 439: gFinderLaunch = NO; ! 440: } ! 441: gArgv = (char**) malloc (sizeof(*gArgv) * (gArgc+1)); ! 442: assert (gArgv != NULL); ! 443: for (i = 0; i < gArgc; i++) ! 444: gArgv[i] = argv[i]; ! 445: gArgv[i] = NULL; ! 446: ! 447: [SDLApplication poseAsClass:[NSApplication class]]; ! 448: NSApplicationMain (argc, (const char**)argv); ! 449: ! 450: return 0; ! 451: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.