1/* SDLMain.m - main entry point for our Cocoa-ized SDL app 2Initial Version: Darrell Walisser <dwaliss1@purdue.edu> 3Non-NIB-Code & other changes: Max Horn <max@quendi.de> 4 5Feel free to customize this file to suit your needs 6*/ 7 8#import "SDL.h" 9#import "SDLMain.h" 10#import <sys/param.h> /* for MAXPATHLEN */ 11#import <unistd.h> 12 13/* Use this flag to determine whether we use SDLMain.nib or not */ 14#define SDL_USE_NIB_FILE 1 15 16 17static int gArgc; 18static char **gArgv; 19static BOOL gFinderLaunch; 20 21#if SDL_USE_NIB_FILE 22/* A helper category for NSString */ 23@interface NSString (ReplaceSubString) 24- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString; 25@end 26#else 27/* An internal Apple class used to setup Apple menus */ 28@interface NSAppleMenuController:NSObject {} 29- (void)controlMenu:(NSMenu *)aMenu; 30@end 31#endif 32 33@interface SDLApplication : NSApplication 34@end 35 36@implementation SDLApplication 37/* Invoked from the Quit menu item */ 38- (void)terminate:(id)sender 39{ 40 /* Post a SDL_QUIT event */ 41 SDL_Event event; 42 event.type = SDL_QUIT; 43 SDL_PushEvent(&event); 44} 45@end 46 47 48/* The main class of the application, the application's delegate */ 49@implementation SDLMain 50 51- (IBAction)prefsMenu:(id)sender 52{ 53 printf ("prefs menu\n"); 54} 55 56- (IBAction)newGame:(id)sender 57{ 58 printf ("new game\n"); 59 60 NSRunAlertPanel (@"Get ready to blow up some... stuff!", 61 @"Click OK to begin total carnage. Click Cancel to prevent total carnage.", @"OK", @"Cancel", nil); 62} 63 64- (IBAction)openGame:(id)sender 65{ 66 NSString *path = nil; 67 NSOpenPanel *openPanel = [ NSOpenPanel openPanel ]; 68 69 if ( [ openPanel runModalForDirectory:nil 70 file:@"SavedGame" types:nil ] ) { 71 72 path = [ [ openPanel filenames ] objectAtIndex:0 ]; 73 } 74 75 printf ("open game: %s\n", [ path cString ]); 76} 77 78- (IBAction)saveGame:(id)sender 79{ 80 NSString *path = nil; 81 NSSavePanel *savePanel = [ NSSavePanel savePanel ]; 82 83 if ( [ savePanel runModalForDirectory:nil 84 file:@"SaveGameFile" ] ) { 85 86 path = [ savePanel filename ]; 87 } 88 89 printf ("save game: %s\n", [ path cString ]); 90} 91 92- (IBAction)saveGameAs:(id)sender 93{ 94 printf ("save game as\n"); 95} 96 97- (IBAction)help:(id)sender 98{ 99 NSRunAlertPanel (@"Oh help, where have ye gone?", 100 @"Sorry, there is no help available.\n\nThis message brought to you by We Don't Document, Inc.\n\n", @"Rats", @"Good, I never read it anyway", nil); 101} 102 103 104/* Set the working directory to the .app's parent directory */ 105- (void) setupWorkingDirectory:(BOOL)shouldChdir 106{ 107 char parentdir[MAXPATHLEN]; 108 char *c; 109 110 strncpy ( parentdir, gArgv[0], sizeof(parentdir) ); 111 c = (char*) parentdir; 112 113 while (*c != '\0') /* go to end */ 114 c++; 115 116 while (*c != '/') /* back up to parent */ 117 c--; 118 119 *c++ = '\0'; /* cut off last part (binary name) */ 120 121 if (shouldChdir) 122 { 123 assert ( chdir (parentdir) == 0 ); /* chdir to the binary app's parent */ 124 assert ( chdir ("../../../") == 0 ); /* chdir to the .app's parent */ 125 } 126} 127 128#if SDL_USE_NIB_FILE 129 130/* Fix menu to contain the real app name instead of "SDL App" */ 131- (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName 132{ 133 NSRange aRange; 134 NSEnumerator *enumerator; 135 NSMenuItem *menuItem; 136 137 aRange = [[aMenu title] rangeOfString:@"SDL App"]; 138 if (aRange.length != 0) 139 [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]]; 140 141 enumerator = [[aMenu itemArray] objectEnumerator]; 142 while ((menuItem = [enumerator nextObject])) 143 { 144 aRange = [[menuItem title] rangeOfString:@"SDL App"]; 145 if (aRange.length != 0) 146 [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]]; 147 if ([menuItem hasSubmenu]) 148 [self fixMenu:[menuItem submenu] withAppName:appName]; 149 } 150 [ aMenu sizeToFit ]; 151} 152 153#else 154 155void setupAppleMenu(void) 156{ 157 /* warning: this code is very odd */ 158 NSAppleMenuController *appleMenuController; 159 NSMenu *appleMenu; 160 NSMenuItem *appleMenuItem; 161 162 appleMenuController = [[NSAppleMenuController alloc] init]; 163 appleMenu = [[NSMenu alloc] initWithTitle:@""]; 164 appleMenuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; 165 166 [appleMenuItem setSubmenu:appleMenu]; 167 168 /* yes, we do need to add it and then remove it -- 169 if you don't add it, it doesn't get displayed 170 if you don't remove it, you have an extra, titleless item in the menubar 171 when you remove it, it appears to stick around 172 very, very odd */ 173 [[NSApp mainMenu] addItem:appleMenuItem]; 174 [appleMenuController controlMenu:appleMenu]; 175 [[NSApp mainMenu] removeItem:appleMenuItem]; 176 [appleMenu release]; 177 [appleMenuItem release]; 178} 179 180/* Create a window menu */ 181void setupWindowMenu(void) 182{ 183 NSMenu *windowMenu; 184 NSMenuItem *windowMenuItem; 185 NSMenuItem *menuItem; 186 187 188 windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; 189 190 /* "Minimize" item */ 191 menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; 192 [windowMenu addItem:menuItem]; 193 [menuItem release]; 194 195 /* Put menu into the menubar */ 196 windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; 197 [windowMenuItem setSubmenu:windowMenu]; 198 [[NSApp mainMenu] addItem:windowMenuItem]; 199 200 /* Tell the application object that this is now the window menu */ 201 [NSApp setWindowsMenu:windowMenu]; 202 203 /* Finally give up our references to the objects */ 204 [windowMenu release]; 205 [windowMenuItem release]; 206} 207 208/* Replacement for NSApplicationMain */ 209void CustomApplicationMain (argc, argv) 210{ 211 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 212 SDLMain *sdlMain; 213 214 /* Ensure the application object is initialised */ 215 [SDLApplication sharedApplication]; 216 217 /* Set up the menubar */ 218 [NSApp setMainMenu:[[NSMenu alloc] init]]; 219 setupAppleMenu(); 220 setupWindowMenu(); 221 222 /* Create SDLMain and make it the app delegate */ 223 sdlMain = [[SDLMain alloc] init]; 224 [NSApp setDelegate:sdlMain]; 225 226 /* Start the main event loop */ 227 [NSApp run]; 228 229 [sdlMain release]; 230 [pool release]; 231} 232 233#endif 234 235/* Called when the internal event loop has just started running */ 236- (void) applicationDidFinishLaunching: (NSNotification *) note 237{ 238 int status; 239 240 /* Set the working directory to the .app's parent directory */ 241 [self setupWorkingDirectory:gFinderLaunch]; 242 243#if SDL_USE_NIB_FILE 244 /* Set the main menu to contain the real app name instead of "SDL App" */ 245 [self fixMenu:[NSApp mainMenu] withAppName:[[NSProcessInfo processInfo] processName]]; 246#endif 247 248 /* Hand off to main application code */ 249 status = SDL_main (gArgc, gArgv); 250 251 /* We're done, thank you for playing */ 252 exit(status); 253} 254@end 255 256 257@implementation NSString (ReplaceSubString) 258 259- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString 260{ 261 unsigned int bufferSize; 262 unsigned int selfLen = [self length]; 263 unsigned int aStringLen = [aString length]; 264 unichar *buffer; 265 NSRange localRange; 266 NSString *result; 267 268 bufferSize = selfLen + aStringLen - aRange.length; 269 buffer = NSAllocateMemoryPages(bufferSize*sizeof(unichar)); 270 271 /* Get first part into buffer */ 272 localRange.location = 0; 273 localRange.length = aRange.location; 274 [self getCharacters:buffer range:localRange]; 275 276 /* Get middle part into buffer */ 277 localRange.location = 0; 278 localRange.length = aStringLen; 279 [aString getCharacters:(buffer+aRange.location) range:localRange]; 280 281 /* Get last part into buffer */ 282 localRange.location = aRange.location + aRange.length; 283 localRange.length = selfLen - localRange.location; 284 [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange]; 285 286 /* Build output string */ 287 result = [NSString stringWithCharacters:buffer length:bufferSize]; 288 289 NSDeallocateMemoryPages(buffer, bufferSize); 290 291 return result; 292} 293 294@end 295 296 297 298#ifdef main 299# undef main 300#endif 301 302 303/* Main entry point to executable - should *not* be SDL_main! */ 304int main (int argc, char **argv) 305{ 306 307 /* Copy the arguments into a global variable */ 308 int i; 309 310 /* This is passed if we are launched by double-clicking */ 311 if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) { 312 gArgc = 1; 313 gFinderLaunch = YES; 314 } else { 315 gArgc = argc; 316 gFinderLaunch = NO; 317 } 318 gArgv = (char**) malloc (sizeof(*gArgv) * (gArgc+1)); 319 assert (gArgv != NULL); 320 for (i = 0; i < gArgc; i++) 321 gArgv[i] = argv[i]; 322 gArgv[i] = NULL; 323 324#if SDL_USE_NIB_FILE 325 [SDLApplication poseAsClass:[NSApplication class]]; 326 NSApplicationMain (argc, argv); 327#else 328 CustomApplicationMain (argc, argv); 329#endif 330 return 0; 331} 332