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