|
|
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:
1.1.1.2 ! root 101: Floppy_InsertDiskIntoDrive(0, szPath, cbPath);
1.1 root 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:
1.1.1.2 ! root 124: Floppy_InsertDiskIntoDrive(1, szPath, cbPath);
1.1 root 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
1.1.1.2 ! root 264: MemorySnapShot_Capture(ConfigureParams.Memory.szMemoryCaptureFileName, TRUE);
1.1 root 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
1.1.1.2 ! root 304: MemorySnapShot_Restore([path cString], TRUE);
1.1 root 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.