|
|
1.1.1.12! root 1: /* ! 2: SDLMain.m - main entry point for our Cocoa-ized SDL app 1.1 root 3: Initial Version: Darrell Walisser <[email protected]> 4: Non-NIB-Code & other changes: Max Horn <[email protected]> 1.1.1.12! root 5: Modifications for Hatari by Miguel Saro and Jerome Vernet 1.1 root 6: 7: Feel free to customize this file to suit your needs 1.1.1.11 root 8: */ 1.1 root 9: 1.1.1.11 root 10: /* Use this flag to determine whether we use SDLMain.nib or not */ 11: #define SDL_USE_NIB_FILE 1 1.1.1.6 root 12: 1.1.1.11 root 13: /* Use this flag to determine whether we use CPS (docking) or not */ 14: #define SDL_USE_CPS 1 1.1.1.6 root 15: 1.1.1.11 root 16: #import "SDL.h" 17: #import "SDLMain.h" 18: #import <sys/param.h> // for MAXPATHLEN 19: #import <unistd.h> 1.1.1.6 root 20: 1.1.1.11 root 21: // for Hatari 22: #import "dialog.h" 23: #import "floppy.h" 24: #import "reset.h" 25: #import "screenSnapShot.h" 26: #import "memorySnapShot.h" 27: #import "sound.h" 28: #import "screen.h" 29: #import "PrefsController.h" 30: #import "Shared.h" 31: #import "video.h" 32: #import "avi_record.h" 33: #import "debugui.h" 34: #import "clocks_timings.h" 35: #import "change.h" 1.1.1.6 root 36: 37: 38: #ifdef SDL_USE_CPS 1.1.1.11 root 39: // Portions of CPS.h 1.1.1.6 root 40: typedef struct CPSProcessSerNum 41: { 42: UInt32 lo; 43: UInt32 hi; 44: } CPSProcessSerNum; 45: 46: extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); 47: extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); 48: extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); 49: 1.1.1.11 root 50: #endif // SDL_USE_CPS 1.1 root 51: 1.1.1.11 root 52: static int gArgc; 53: static char **gArgv; 54: static BOOL gFinderLaunch = NO ; 55: static BOOL gCalledAppMainline = NO ; 1.1.1.6 root 56: 57: 1.1.1.11 root 58: // The main class of the application, the application's delegate 59: // 60: @implementation HatariAppDelegate 1.1 root 61: 1.1.1.11 root 62: char szPath[FILENAME_MAX] ; // for general use 1.1 root 63: 1.1.1.11 root 64: // Set the working directory to the .app's parent directory 1.1.1.6 root 65: - (void) setupWorkingDirectory:(BOOL)shouldChdir 66: { 1.1.1.12! root 67: if (shouldChdir) 1.1.1.11 root 68: chdir([[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] cStringUsingEncoding:NSASCIIStringEncoding]) ; 1.1.1.6 root 69: } 70: 71: 72: /* 73: * Catch document open requests...this lets us notice files when the app 74: * was launched by double-clicking a document, or when a document was 75: * dragged/dropped on the app's icon. You need to have a 76: * CFBundleDocumentsType section in your Info.plist to get this message, 77: * apparently. 78: * 79: * Files are added to gArgv, so to the app, they'll look like command line 80: * arguments. Previously, apps launched from the finder had nothing but 81: * an argv[0]. 82: * 83: * This message may be received multiple times to open several docs on launch. 84: * 85: * This message is ignored once the app's mainline has been called. 86: */ 87: - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename 88: { 1.1.1.12! root 89: const char *temparg; ! 90: size_t arglen; ! 91: char *arg; ! 92: char **newargv; ! 93: ! 94: if (!gFinderLaunch) // MacOS is passing command line args. ! 95: return FALSE; ! 96: ! 97: if (gCalledAppMainline) // app has started, ignore this document. ! 98: return FALSE; ! 99: ! 100: temparg = [filename UTF8String] ; ! 101: arglen = SDL_strlen(temparg) + 1 ; ! 102: arg = (char *) SDL_malloc(arglen) ; ! 103: if (arg == NULL) ! 104: return FALSE; ! 105: ! 106: newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2)) ; ! 107: if (newargv == NULL) ! 108: { ! 109: SDL_free(arg); ! 110: return FALSE; ! 111: } ! 112: gArgv = newargv ; ! 113: ! 114: SDL_strlcpy(arg, temparg, arglen) ; ! 115: gArgv[gArgc++] = arg ; ! 116: gArgv[gArgc] = NULL ; ! 117: return TRUE; 1.1.1.6 root 118: } 119: 120: 1.1.1.11 root 121: // Called when the internal event loop has just started running 122: // 1.1.1.6 root 123: - (void) applicationDidFinishLaunching: (NSNotification *) note 124: { 1.1.1.11 root 125: int status; 1.1.1.6 root 126: 1.1.1.11 root 127: // Set the working directory to the .app's parent directory 128: [self setupWorkingDirectory:gFinderLaunch]; 1.1.1.6 root 129: 1.1.1.11 root 130: //setenv ("SDL_ENABLEAPPEVENTS", "1", 1) ; 1.1.1.6 root 131: 1.1.1.11 root 132: // Hand off to main application code 1.1.1.6 root 133: 1.1.1.11 root 134: gCalledAppMainline = TRUE; 135: status = SDL_main (gArgc, gArgv) ; 136: 137: // We're done, thank you for playing 138: exit(status) ; 1.1.1.6 root 139: } 140: 141: // Hatari Stuff 1.1 root 142: - (IBAction)prefsMenu:(id)sender 143: { 144: static int in_propdialog = 0; 1.1.1.6 root 145: 1.1 root 146: if (in_propdialog) 1.1.1.11 root 147: return ; 148: ++in_propdialog ; 149: Dialog_DoProperty() ; 1.1 root 150: --in_propdialog; 151: } 152: 1.1.1.11 root 153: /*- (IBAction) openPreferences:(id)sender 1.1.1.9 root 154: { 155: [[PrefsController prefs] loadPrefs:sender]; 1.1.1.11 root 156: } // */ 1.1.1.9 root 157: 158: 1.1.1.6 root 159: - (IBAction)debugUI:(id)sender 160: { 1.1.1.8 root 161: DebugUI(REASON_USER); 1.1.1.6 root 162: } 163: 1.1 root 164: - (IBAction)warmReset:(id)sender 165: { 1.1.1.12! root 166: if ([NSApp myAlerte:NSInformationalAlertStyle Txt:localize(@"Warm reset!") firstB:localize(@"OK") alternateB:localize(@"Cancel") ! 167: otherB:nil informativeTxt:localize(@"Really reset the emulator?")] == NSAlertDefaultReturn) 1.1 root 168: Reset_Warm(); 1.1.1.10 root 169: } 1.1 root 170: 171: - (IBAction)coldReset:(id)sender 172: { 1.1.1.12! root 173: if ([NSApp myAlerte:NSInformationalAlertStyle Txt:localize(@"Cold reset") firstB:localize(@"OK") alternateB:localize(@"Cancel") ! 174: otherB:nil informativeTxt:localize(@"Really reset the emulator?")] == NSAlertDefaultReturn) 1.1 root 175: Reset_Cold(); 176: } 177: 178: - (IBAction)insertDiskA:(id)sender 179: { 1.1.1.11 root 180: [self insertDisk:0] ; 1.1 root 181: } 182: 183: - (IBAction)insertDiskB:(id)sender 184: { 1.1.1.11 root 185: [self insertDisk:1] ; 186: } 1.1.1.6 root 187: 1.1.1.11 root 188: - (void)insertDisk:(int)disque 189: { 190: NSString *aDisk ; 1.1.1.6 root 191: 1.1.1.11 root 192: aDisk = [NSApp hopenfile:NO defoDir:nil defoFile:@"" types:[NSArray arrayWithObjects:allF,nil]] ; 193: if ([aDisk length] == 0) return ; // user canceled 1.1.1.6 root 194: 1.1.1.11 root 195: [aDisk getCString:szPath maxLength:FILENAME_MAX-1 encoding:NSASCIIStringEncoding] ; 196: Floppy_SetDiskFileName(disque, szPath, NULL) ; 197: Floppy_InsertDiskIntoDrive(disque) ; 1.1 root 198: } 199: 1.1.1.11 root 200: 1.1 root 201: /*-----------------------------------------------------------------------*/ 202: /* 1.1.1.6 root 203: Controls the enabled state of the menu items 204: */ 1.1 root 205: - (BOOL)validateMenuItem:(NSMenuItem*)item 206: { 207: if (item == beginCaptureAnim) 208: { 1.1.1.11 root 209: return !Avi_AreWeRecording() ; 1.1 root 210: } 211: if (item == endCaptureAnim) 212: { 1.1.1.11 root 213: return Avi_AreWeRecording() ; 1.1 root 214: } 215: if (item == beginCaptureSound) 216: { 1.1.1.11 root 217: return !Sound_AreWeRecording() ; 1.1 root 218: } 219: if (item == endCaptureSound) 220: { 1.1.1.11 root 221: return Sound_AreWeRecording() ; 1.1 root 222: } 223: 224: return YES; 225: } 226: 1.1.1.7 root 227: - (NSString*)displayFileSelection:(const char*)pathInParams preferredFileName:(NSString*)preferredFileName allowedExtensions:(NSArray*)allowedExtensions 1.1 root 228: { 1.1.1.11 root 229: // BOOL test ; 230: NSString *directoryToOpen; 231: NSString *fileToPreselect; 232: NSString *preferredPath; 233: NSString *extensionText; 234: NSString *selectFile; 1.1.1.12! root 235: 1.1 root 236: // Get the path from the user settings 1.1.1.11 root 237: preferredPath = [[NSString stringWithCString:pathInParams encoding:NSASCIIStringEncoding] stringByAbbreviatingWithTildeInPath]; 238: 239: if ((preferredPath != nil) && ([preferredPath length] > 0)) // Determine the directory and filename 240: { 241: directoryToOpen = [preferredPath stringByDeletingLastPathComponent]; // Existing path: we use it 1.1 root 242: fileToPreselect = [preferredPath lastPathComponent]; 1.1.1.11 root 243: } 1.1 root 244: else 1.1.1.11 root 245: { 246: directoryToOpen = [@"~" stringByExpandingTildeInPath]; // No path: we use the user's directory 1.1.1.7 root 247: fileToPreselect = preferredFileName; 1.1.1.11 root 248: } ; 1.1.1.12! root 249: 1.1.1.11 root 250: if(bInFullScreen) 251: Screen_ReturnFromFullScreen(); 252: // SavePanel for choosing what file to write 253: extensionText = [NSString stringWithFormat:localize(@"Please specify a .%@ file"), [allowedExtensions componentsJoinedByString:localize(@" or a .")] ]; 1.1.1.12! root 254: 1.1.1.11 root 255: selectFile = [NSApp hsavefile:YES defoDir:directoryToOpen defoFile:fileToPreselect types:allowedExtensions titre:extensionText ] ; 256: if ([selectFile length] != 0 ) 257: return selectFile ; 1.1.1.12! root 258: 1.1.1.7 root 259: return nil; 260: } 261: 262: - (IBAction)captureScreen:(id)sender 263: { 264: GuiOsx_Pause(); 265: ScreenSnapShot_SaveScreen(); 266: GuiOsx_Resume(); 267: } 268: 269: - (IBAction)captureAnimation:(id)sender 270: { 271: GuiOsx_Pause(); 272: if(!Avi_AreWeRecording()) { 1.1.1.12! root 273: NSString* path = [self displayFileSelection:ConfigureParams.Video.AviRecordFile preferredFileName:@"hatari.avi" 1.1.1.11 root 274: allowedExtensions:[NSArray arrayWithObject:@"avi"]]; 1.1.1.12! root 275: 1.1.1.7 root 276: if(path) { 277: GuiOsx_ExportPathString(path, ConfigureParams.Video.AviRecordFile, sizeof(ConfigureParams.Video.AviRecordFile)); 278: Avi_StartRecording ( ConfigureParams.Video.AviRecordFile , ConfigureParams.Screen.bCrop , 279: ConfigureParams.Video.AviRecordFps == 0 ? 280: ClocksTimings_GetVBLPerSec ( ConfigureParams.System.nMachineType , nScreenRefreshRate ) : 281: (Uint32)ConfigureParams.Video.AviRecordFps << CLOCKS_TIMINGS_SHIFT_VBL , 282: 1 << CLOCKS_TIMINGS_SHIFT_VBL , 283: ConfigureParams.Video.AviRecordVcodec ); 284: } 285: } else { 286: Avi_StopRecording(); 1.1.1.6 root 287: } 1.1.1.7 root 288: GuiOsx_Resume(); 289: } 1.1 root 290: 1.1.1.7 root 291: - (IBAction)endCaptureAnimation:(id)sender 292: { 1.1.1.11 root 293: GuiOsx_Pause(); 294: Avi_StopRecording(); 295: GuiOsx_Resume(); 1.1.1.7 root 296: } 297: 298: - (IBAction)captureSound:(id)sender 299: { 300: GuiOsx_Pause(); 1.1.1.12! root 301: NSString* path = [self displayFileSelection:ConfigureParams.Sound.szYMCaptureFileName preferredFileName:@"hatari.wav" 1.1.1.7 root 302: allowedExtensions:[NSArray arrayWithObjects:@"ym", @"wav", nil]]; 303: if(path) { 304: GuiOsx_ExportPathString(path, ConfigureParams.Sound.szYMCaptureFileName, sizeof(ConfigureParams.Sound.szYMCaptureFileName)); 305: Sound_BeginRecording(ConfigureParams.Sound.szYMCaptureFileName); 306: } 1.1.1.5 root 307: GuiOsx_Resume(); 1.1 root 308: } 309: 310: - (IBAction)endCaptureSound:(id)sender 311: { 1.1.1.5 root 312: GuiOsx_Pause(); 1.1 root 313: Sound_EndRecording(); 1.1.1.5 root 314: GuiOsx_Resume(); 1.1 root 315: } 316: 317: - (IBAction)saveMemorySnap:(id)sender 318: { 1.1.1.5 root 319: GuiOsx_Pause(); 1.1 root 320: 1.1.1.12! root 321: NSString* path = [self displayFileSelection:ConfigureParams.Memory.szMemoryCaptureFileName preferredFileName:@"hatari.sav" 1.1.1.11 root 322: allowedExtensions:[NSArray arrayWithObject:@"sav"]]; 1.1.1.7 root 323: if(path) { 1.1 root 324: GuiOsx_ExportPathString(path, ConfigureParams.Memory.szMemoryCaptureFileName, sizeof(ConfigureParams.Memory.szMemoryCaptureFileName)); 1.1.1.2 root 325: MemorySnapShot_Capture(ConfigureParams.Memory.szMemoryCaptureFileName, TRUE); 1.1.1.6 root 326: } 1.1.1.12! root 327: 1.1.1.5 root 328: GuiOsx_Resume(); 1.1 root 329: } 330: 331: - (IBAction)restoreMemorySnap:(id)sender 332: { 1.1.1.12! root 333: NSString *directoryToOpen; ! 334: NSString *fileToPreselect; ! 335: NSString *oldPath ; ! 336: NSString *newPath ; 1.1 root 337: 1.1.1.11 root 338: GuiOsx_Pause(); 1.1 root 339: 340: // Get the path from the user settings 1.1.1.11 root 341: oldPath = [NSString stringWithCString:(ConfigureParams.Memory.szMemoryCaptureFileName) encoding:NSASCIIStringEncoding]; 1.1.1.12! root 342: 1.1.1.11 root 343: if ((oldPath != nil) && ([oldPath length] > 0)) // Determine directory and filename 344: { directoryToOpen = [oldPath stringByDeletingLastPathComponent]; // existing path: we use it. 345: fileToPreselect = [oldPath lastPathComponent]; } 1.1 root 346: else 1.1.1.11 root 347: { directoryToOpen = [@"~" stringByExpandingTildeInPath]; // Currently no path: we use user's directory 348: fileToPreselect = nil; } ; 1.1.1.6 root 349: 1.1.1.11 root 350: newPath = [NSApp hopenfile:NO defoDir:directoryToOpen defoFile:fileToPreselect types:[NSArray arrayWithObject:@"sav"] ] ; 351: if ([newPath length] != 0) // Perform the memory snapshot load 352: MemorySnapShot_Restore([newPath cStringUsingEncoding:NSASCIIStringEncoding], TRUE); 1.1.1.6 root 353: 1.1.1.5 root 354: GuiOsx_Resume(); 1.1 root 355: } 356: 357: - (IBAction)doFullScreen:(id)sender 358: { 1.1.1.12! root 359: // A call to Screen_EnterFullScreen() would be required, but this causes a crash when using 1.1.1.11 root 360: // SDL runtime 1.2.11, probably due to conflicts between Cocoa and SDL. 1.1 root 361: // Therefore we simulate the fullscreen key press instead 1.1.1.12! root 362: 1.1 root 363: SDL_KeyboardEvent event; 1.1.1.12! root 364: memset(&event, 0, sizeof(event)); 1.1.1.6 root 365: event.type = SDL_KEYDOWN; 366: event.state = SDL_PRESSED; 367: event.keysym.sym = SDLK_F11; 368: SDL_PushEvent((SDL_Event*)&event); // Send the F11 key press 369: event.type = SDL_KEYUP; 370: event.state = SDL_RELEASED; 371: SDL_PushEvent((SDL_Event*)&event); // Send the F11 key release 1.1 root 372: } 373: 1.1.1.9 root 374: 1.1 root 375: - (IBAction)help:(id)sender 376: { 1.1.1.11 root 377: NSString *the_help; 1.1.1.12! root 378: 1.1.1.11 root 379: the_help = [[NSBundle mainBundle] pathForResource:@"manual" ofType:@"html" inDirectory:@"HatariHelp"]; 1.1.1.12! root 380: 1.1.1.11 root 381: if (![[NSWorkspace sharedWorkspace] openFile:the_help withApplication:@"HelpViewer"]) 382: if (![[NSWorkspace sharedWorkspace] openFile:the_help withApplication:@"Help Viewer"]) 383: [[NSWorkspace sharedWorkspace] openFile:the_help]; 1.1 root 384: } 385: 1.1.1.10 root 386: - (IBAction)compat:(id)sender 387: { 1.1.1.12! root 388: NSString *C_aide ; ! 389: 1.1.1.11 root 390: C_aide = [[NSBundle mainBundle] pathForResource:@"compatibility" ofType:@"html" inDirectory:@"HatariHelp"] ; 1.1.1.12! root 391: 1.1.1.10 root 392: if (![[NSWorkspace sharedWorkspace] openFile:C_aide withApplication:@"HelpViewer"]) 393: if (![[NSWorkspace sharedWorkspace] openFile:C_aide withApplication:@"Help Viewer"]) 1.1.1.12! root 394: [[NSWorkspace sharedWorkspace] openFile:C_aide] ; 1.1.1.10 root 395: } 1.1 root 396: 1.1.1.12! root 397: - (IBAction)openConfig:(id)sender 1.1.1.9 root 398: { 1.1.1.12! root 399: BOOL applyChanges ; ! 400: NSString *ConfigFile, *newCfg ; ! 401: CNF_PARAMS CurrentParams; 1.1.1.11 root 402: 403: applyChanges = true ; 1.1.1.12! root 404: ConfigFile = [NSString stringWithCString:(sConfigFileName) encoding:NSASCIIStringEncoding]; ! 405: 1.1.1.9 root 406: // Backup of configuration settings to CurrentParams (which we will only 407: // commit back to the configuration settings if choosing user confirm) 408: CurrentParams = ConfigureParams; 1.1.1.12! root 409: 1.1.1.9 root 410: GuiOsx_Pause(); 1.1.1.12! root 411: 1.1.1.11 root 412: newCfg = [NSApp hopenfile:NO defoDir:nil defoFile:ConfigFile types:[NSArray arrayWithObject:@"cfg"] ] ; 1.1.1.12! root 413: 1.1.1.11 root 414: if ([newCfg length] != 0) 1.1.1.12! root 415: { 1.1.1.11 root 416: [newCfg getCString:szPath maxLength:FILENAME_MAX-1 encoding:NSASCIIStringEncoding] ; // get Cstring szPath 417: Configuration_Load(szPath) ; // Load the config into ConfigureParams 418: strcpy(sConfigFileName,szPath) ; 419: 1.1.1.12! root 420: // Refresh all the controls to match ConfigureParams 1.1.1.9 root 421: if (Change_DoNeedReset(&CurrentParams, &ConfigureParams)) 1.1.1.12! root 422: applyChanges = [NSApp myAlerte:NSInformationalAlertStyle Txt:localize(@"Reset the emulator") firstB:localize(@"Don't reset") ! 423: alternateB:localize(@"Reset") otherB:nil informativeTxt:@"" ] == NSAlertAlternateReturn ; 1.1.1.9 root 424: if (applyChanges) 1.1.1.11 root 425: Change_CopyChangedParamsToConfiguration(&CurrentParams, &ConfigureParams, true); // Ok with Reset 1.1.1.12! root 426: else 1.1.1.11 root 427: ConfigureParams = CurrentParams; //Restore previous Params. 1.1.1.12! root 428: } ; ! 429: 1.1.1.9 root 430: GuiOsx_Resume(); 1.1 root 431: } 432: 1.1.1.9 root 433: 1.1.1.6 root 434: - (IBAction)saveConfig:(id)sender { 1.1 root 435: } 436: 437: @end 438: 1.1.1.12! root 439: static int IsRootCwd() ! 440: { ! 441: char buf[MAXPATHLEN]; ! 442: char *cwd = getcwd(buf, sizeof (buf)); ! 443: return (cwd && (strcmp(cwd, "/") == 0)); ! 444: } ! 445: ! 446: static int IsTenPointNineOrLater() ! 447: { ! 448: /* Gestalt() is deprecated in 10.8 ... TODO: replace with better test? */ ! 449: SInt32 major, minor; ! 450: Gestalt(gestaltSystemVersionMajor, &major); ! 451: Gestalt(gestaltSystemVersionMinor, &minor); ! 452: return ( ((major << 16) | minor) >= ((10 << 16) | 9) ); ! 453: } ! 454: ! 455: static int IsFinderLaunch(const int argc, char **argv) ! 456: { ! 457: /* -psn_XXX is passed if we are launched from Finder in 10.8 and earlier */ ! 458: if (argc >= 2 && strncmp(argv[1], "-psn", 4) == 0) { ! 459: return 1; ! 460: } ! 461: if (IsTenPointNineOrLater() && argc == 1 && IsRootCwd()) { ! 462: /* we might still be launched from the Finder; on 10.9+, you might not ! 463: get the -psn command line anymore. Check version, if there's no ! 464: command line, and if our current working directory is "/". */ ! 465: return 1; ! 466: } ! 467: return 0; /* not a Finder launch. */ ! 468: } ! 469: 1.1 root 470: #ifdef main 471: # undef main 472: #endif 473: 1.1.1.12! root 474: // Main entry point to executable - should *not* be SDL_main! 1.1 root 475: int main (int argc, char **argv) 476: { 1.1.1.12! root 477: // Copy the arguments into a global variable ! 478: if (IsFinderLaunch(argc, argv)) { ! 479: gArgv = (char **) SDL_malloc(sizeof (char *) * 2); ! 480: gArgv[0] = argv[0]; ! 481: gArgv[1] = NULL; ! 482: gArgc = 1; ! 483: gFinderLaunch = YES; ! 484: } else { ! 485: int i; ! 486: gArgc = argc; ! 487: gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1)); ! 488: for (i = 0; i <= argc; i++) ! 489: gArgv[i] = argv[i]; ! 490: gFinderLaunch = NO; ! 491: } 1.1 root 492: 1.1.1.6 root 493: #if SDL_USE_NIB_FILE 1.1.1.12! root 494: NSApplicationMain (argc, (const char**)argv); 1.1.1.6 root 495: #else 1.1.1.12! root 496: CustomApplicationMain (argc, argv); 1.1.1.6 root 497: #endif 1.1.1.12! root 498: return 0; ! 499: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.