1// SDLMain.M - main entry point for a Cocoa-ized SDL app 2 3 4 5 6#import "SDL_compat.h" 7#import "SDLMain.h" 8#import <sys/param.h> /* for MAXPATHLEN */ 9#import <unistd.h> 10 11#import "host.h" 12 13 14 15 16#define UNUSED(param) ((void)param) 17 18 19 20 21static int gArgc; 22static char **gArgv; 23static bool gFinderLaunch; 24static bool gCalledAppMainline(false); 25static char* gConfigFile(NULL); 26 27 28 29 30 31 32 33 34// The main class of the application, the application's delegate. 35@implementation SDLMain 36 37 38 39 40// Catch document open requests. 41// Files are added to gArgv, so to the app, they'll look like command line arguments. 42// This message may be received multiple times to open several docs on launch. 43// This message is ignored once the app's mainline has been called. 44- (BOOL) application: (NSApplication *) theApplication openFile: (NSString *) filename { 45 UNUSED(theApplication); 46 47 size_t filenamelen; 48 const char* configfile; 49 char** argv; 50 51 if (gCalledAppMainline) 52 // The pplication has already been started, ignore this document. 53 return(false); 54 55 if (!gFinderLaunch) 56 // Command line arguments have been passed. 57 return(false); 58 59 // The gFinderLaunch is set, thus argv was "<app> -psn <number>" and gArgv now is "<app>". 60 // As there is space left in original agrv to now hold "<app> -c <config>". 61 62 BOOL isDir; 63 NSFileManager* fileManager = [NSFileManager defaultManager]; 64 if ([fileManager fileExistsAtPath: filename isDirectory: &isDir]) { 65 if (isDir) { 66 NSString* configfilename; 67 68 configfilename = [filename stringByAppendingPathComponent: @ARANYMCONFIG]; 69 if ([fileManager fileExistsAtPath: configfilename]) { 70 filename = configfilename; 71 } else { 72 [configfilename release]; 73 configfilename = [filename stringByAppendingPathComponent: @"config"]; 74 if ([fileManager fileExistsAtPath: configfilename]) { 75 filename = configfilename; 76 } else { 77 [configfilename release]; 78 return(false); 79 } 80 } 81 } 82 83 // Allocate memory to keep the config file name. 84 configfile = [filename UTF8String]; 85 filenamelen = SDL_strlen(configfile) + 1; 86 gConfigFile = (char *)SDL_malloc(filenamelen); 87 if (gConfigFile == NULL) 88 return(false); 89 SDL_strlcpy(gConfigFile, configfile, filenamelen); 90 91 // Allocate memory to hold the new argument pointers. 92 argv = (char**)SDL_malloc(4 * sizeof(char*)); 93 if (argv == NULL) { 94 SDL_free(gConfigFile); 95 gConfigFile = NULL; 96 return(false); 97 } 98 99 // Build the "<app> -c <cofing>" arguments. 100 argv[0] = gArgv[0]; 101 argv[1] = "-c"; 102 argv[2] = gConfigFile; 103 argv[3] = NULL; 104 105 // Set the new into the global arguments. 106 gArgv = argv; 107 gArgc = 3; 108 109 // ARAnyM can only handle a single config file, thus this flag is set to ignore further files. 110 gCalledAppMainline = true; 111 } 112 return(true); 113} 114 115 116 117 118// Called when the internal event loop has just started running. 119- (void) applicationDidFinishLaunching: (NSNotification *) aNotification { 120 UNUSED(aNotification); 121 int status; 122 123 // Remember that application has started. 124 gCalledAppMainline = true; 125 SDL_SetMainReady(); 126 127 // Hand over to main application code. 128 status = SDL_main(gArgc, gArgv); 129 130 // Terminate the application. 131 //[NSApp terminate: NSApp]; 132 //[NSApp stop: self]; 133 134 // Release fake arguments again. 135 if (gConfigFile != NULL) { 136 SDL_free(gArgv); 137 SDL_free(gConfigFile); 138 } 139 140 // We're done, thank you for playing. 141 exit(status); 142} 143 144 145 146 147// Called when the application should terminate. 148- (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication *) theApplication { 149 UNUSED(theApplication); 150 // Post a SDL_QUIT event 151 SDL_Event event; 152 event.type = SDL_QUIT; 153 SDL_PushEvent(&event); 154 // Cancel the termination, as the SDL_QUIT signal will finally lead to an exit() call. 155 return(NSTerminateCancel); 156} 157 158 159 160 161// The user selected the "Preferencs..." menu entry. 162- (IBAction) showPrefs: (id) sender { 163 UNUSED(sender); 164 SDL_Event event; 165 event.type = SDL_KEYDOWN; 166 event.key.keysym.sym = bx_options.hotkeys.setup.sym; 167 event.key.keysym.mod = bx_options.hotkeys.setup.mod; 168 SDL_PushEvent(&event); 169} 170 171 172 173 174// The user selected the "Fullscreen" menu entry. 175- (IBAction) makeFullscreen: (id) sender { 176 UNUSED(sender); 177 SDL_Event event; 178 event.type = SDL_KEYDOWN; 179 event.key.keysym.sym = bx_options.hotkeys.fullscreen.sym; 180 event.key.keysym.mod = bx_options.hotkeys.fullscreen.mod; 181 SDL_PushEvent(&event); 182} 183 184 185 186 187// The user selected the "Screenshot" menu entry. 188- (IBAction) makeScreenshot: (id) sender { 189 UNUSED(sender); 190 SDL_Event event; 191 event.type = SDL_KEYDOWN; 192 event.key.keysym.sym = bx_options.hotkeys.screenshot.sym; 193 event.key.keysym.mod = bx_options.hotkeys.screenshot.mod; 194 SDL_PushEvent(&event); 195} 196 197 198 199 200// The user selected the "Reboot" menu entry */ 201- (IBAction) reboot: (id) sender { 202 UNUSED(sender); 203 SDL_Event event; 204 event.type = SDL_KEYDOWN; 205 event.key.keysym.sym = bx_options.hotkeys.reboot.sym; 206 event.key.keysym.mod = bx_options.hotkeys.reboot.mod; 207 SDL_PushEvent(&event); 208} 209 210 211 212 213// The user selected the "Debug" menu entry. 214- (IBAction) debug: (id) sender { 215 UNUSED(sender); 216 SDL_Event event; 217 event.type = SDL_KEYDOWN; 218 event.key.keysym.sym = bx_options.hotkeys.debug.sym; 219 event.key.keysym.mod = bx_options.hotkeys.debug.mod; 220 SDL_PushEvent(&event); 221} 222 223 224 225 226@end 227 228 229 230 231#ifdef main 232 #undef main 233#endif 234 235 236 237 238static int IsRootCwd(void) 239{ 240 char buf[MAXPATHLEN]; 241 char *cwd = getcwd(buf, sizeof (buf)); 242 return cwd != NULL && strcmp(cwd, "/") == 0; 243} 244 245static int IsFinderLaunch(int argc, char **argv) 246{ 247 /* -psn_XXX is passed if we are launched from Finder, SOMETIMES */ 248 if ( (argc >= 2) && (strncmp(argv[1], "-psn", 4) == 0) ) { 249 return 1; 250 } else if ((argc == 1) && IsRootCwd()) { 251 /* we might still be launched from the Finder; on 10.9+, you might not 252 get the -psn command line anymore. If there's no 253 command line, and if our current working directory is "/", it 254 might as well be a Finder launch. */ 255 return 1; 256 } 257 return 0; /* not a Finder launch. */ 258} 259 260 261// Main entry point to executable. 262int main (int argc, char **argv) { 263 // Copy the arguments into a global variable. 264 265 // This is passed if we are launched by double-clicking. 266 if (IsFinderLaunch(argc, argv)) { 267 gArgc = 1; 268 gArgv = argv; 269 gArgv[1] = NULL; 270 gFinderLaunch = true; 271 } else { 272 gArgc = argc; 273 gArgv = argv; 274 gFinderLaunch = false; 275 } 276 277 NSApplicationMain(argc, const_cast<const char**>(argv)); 278 279 return(0); 280} 281