|
|
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: Feel free to customize this file to suit your needs ! 6: */ ! 7: ! 8: #include "SDL.h" ! 9: #include "SDLMain.h" ! 10: #include <sys/param.h> /* for MAXPATHLEN */ ! 11: #include <unistd.h> ! 12: ! 13: /* For some reaon, Apple removed setAppleMenu from the headers in 10.4, ! 14: but the method still is there and works. To avoid warnings, we declare ! 15: it ourselves here. */ ! 16: @interface NSApplication(SDL_Missing_Methods) ! 17: - (void)setAppleMenu:(NSMenu *)menu; ! 18: @end ! 19: ! 20: /* Use this flag to determine whether we use SDLMain.nib or not */ ! 21: #define SDL_USE_NIB_FILE 0 ! 22: ! 23: /* Use this flag to determine whether we use CPS (docking) or not */ ! 24: #define SDL_USE_CPS 1 ! 25: #ifdef SDL_USE_CPS ! 26: /* Portions of CPS.h */ ! 27: typedef struct CPSProcessSerNum ! 28: { ! 29: UInt32 lo; ! 30: UInt32 hi; ! 31: } CPSProcessSerNum; ! 32: ! 33: extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); ! 34: extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); ! 35: extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); ! 36: ! 37: #endif /* SDL_USE_CPS */ ! 38: ! 39: static int gArgc; ! 40: static char **gArgv; ! 41: static BOOL gFinderLaunch; ! 42: static BOOL gCalledAppMainline = FALSE; ! 43: ! 44: static NSString *getApplicationName(void) ! 45: { ! 46: const NSDictionary *dict; ! 47: NSString *appName = 0; ! 48: ! 49: /* Determine the application name */ ! 50: dict = (const NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()); ! 51: if (dict) ! 52: appName = [dict objectForKey: @"CFBundleName"]; ! 53: ! 54: if (![appName length]) ! 55: appName = [[NSProcessInfo processInfo] processName]; ! 56: ! 57: return appName; ! 58: } ! 59: ! 60: #if SDL_USE_NIB_FILE ! 61: /* A helper category for NSString */ ! 62: @interface NSString (ReplaceSubString) ! 63: - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString; ! 64: @end ! 65: #endif ! 66: ! 67: @interface NSApplication (SDLApplication) ! 68: @end ! 69: ! 70: @implementation NSApplication (SDLApplication) ! 71: /* Invoked from the Quit menu item */ ! 72: - (void)terminate:(id)sender ! 73: { ! 74: /* Post a SDL_QUIT event */ ! 75: SDL_Event event; ! 76: event.type = SDL_QUIT; ! 77: SDL_PushEvent(&event); ! 78: } ! 79: @end ! 80: ! 81: /* The main class of the application, the application's delegate */ ! 82: @implementation SDLMain ! 83: ! 84: /* Set the working directory to the .app's parent directory */ ! 85: - (void) setupWorkingDirectory:(BOOL)shouldChdir ! 86: { ! 87: if (shouldChdir) ! 88: { ! 89: char parentdir[MAXPATHLEN]; ! 90: CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); ! 91: CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url); ! 92: if (CFURLGetFileSystemRepresentation(url2, 1, (UInt8 *)parentdir, MAXPATHLEN)) { ! 93: chdir(parentdir); /* chdir to the binary app's parent */ ! 94: } ! 95: CFRelease(url); ! 96: CFRelease(url2); ! 97: } ! 98: } ! 99: ! 100: #if SDL_USE_NIB_FILE ! 101: ! 102: /* Fix menu to contain the real app name instead of "SDL App" */ ! 103: - (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName ! 104: { ! 105: NSRange aRange; ! 106: NSEnumerator *enumerator; ! 107: NSMenuItem *menuItem; ! 108: ! 109: aRange = [[aMenu title] rangeOfString:@"SDL App"]; ! 110: if (aRange.length != 0) ! 111: [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]]; ! 112: ! 113: enumerator = [[aMenu itemArray] objectEnumerator]; ! 114: while ((menuItem = [enumerator nextObject])) ! 115: { ! 116: aRange = [[menuItem title] rangeOfString:@"SDL App"]; ! 117: if (aRange.length != 0) ! 118: [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]]; ! 119: if ([menuItem hasSubmenu]) ! 120: [self fixMenu:[menuItem submenu] withAppName:appName]; ! 121: } ! 122: } ! 123: ! 124: #else ! 125: ! 126: static void setApplicationMenu(void) ! 127: { ! 128: /* warning: this code is very odd */ ! 129: NSMenu *appleMenu; ! 130: NSMenuItem *menuItem; ! 131: NSString *title; ! 132: NSString *appName; ! 133: ! 134: appName = getApplicationName(); ! 135: appleMenu = [[NSMenu alloc] initWithTitle:@""]; ! 136: ! 137: /* Add menu items */ ! 138: title = [@"About " stringByAppendingString:appName]; ! 139: [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; ! 140: ! 141: [appleMenu addItem:[NSMenuItem separatorItem]]; ! 142: ! 143: title = [@"Hide " stringByAppendingString:appName]; ! 144: [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; ! 145: ! 146: menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; ! 147: [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; ! 148: ! 149: [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; ! 150: ! 151: [appleMenu addItem:[NSMenuItem separatorItem]]; ! 152: ! 153: title = [@"Quit " stringByAppendingString:appName]; ! 154: [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; ! 155: ! 156: ! 157: /* Put menu into the menubar */ ! 158: menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; ! 159: [menuItem setSubmenu:appleMenu]; ! 160: [[NSApp mainMenu] addItem:menuItem]; ! 161: ! 162: /* Tell the application object that this is now the application menu */ ! 163: [NSApp setAppleMenu:appleMenu]; ! 164: ! 165: /* Finally give up our references to the objects */ ! 166: [appleMenu release]; ! 167: [menuItem release]; ! 168: } ! 169: ! 170: /* Create a window menu */ ! 171: static void setupWindowMenu(void) ! 172: { ! 173: NSMenu *windowMenu; ! 174: NSMenuItem *windowMenuItem; ! 175: NSMenuItem *menuItem; ! 176: ! 177: windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; ! 178: ! 179: /* "Minimize" item */ ! 180: menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; ! 181: [windowMenu addItem:menuItem]; ! 182: [menuItem release]; ! 183: ! 184: /* Put menu into the menubar */ ! 185: windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; ! 186: [windowMenuItem setSubmenu:windowMenu]; ! 187: [[NSApp mainMenu] addItem:windowMenuItem]; ! 188: ! 189: /* Tell the application object that this is now the window menu */ ! 190: [NSApp setWindowsMenu:windowMenu]; ! 191: ! 192: /* Finally give up our references to the objects */ ! 193: [windowMenu release]; ! 194: [windowMenuItem release]; ! 195: } ! 196: ! 197: /* Replacement for NSApplicationMain */ ! 198: static void CustomApplicationMain (int argc, char **argv) ! 199: { ! 200: NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; ! 201: SDLMain *sdlMain; ! 202: ! 203: /* Ensure the application object is initialised */ ! 204: [NSApplication sharedApplication]; ! 205: ! 206: #ifdef SDL_USE_CPS ! 207: { ! 208: CPSProcessSerNum PSN; ! 209: /* Tell the dock about us */ ! 210: if (!CPSGetCurrentProcess(&PSN)) ! 211: if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) ! 212: if (!CPSSetFrontProcess(&PSN)) ! 213: [NSApplication sharedApplication]; ! 214: } ! 215: #endif /* SDL_USE_CPS */ ! 216: ! 217: /* Set up the menubar */ ! 218: [NSApp setMainMenu:[[NSMenu alloc] init]]; ! 219: setApplicationMenu(); ! 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: ! 236: /* ! 237: * Catch document open requests...this lets us notice files when the app ! 238: * was launched by double-clicking a document, or when a document was ! 239: * dragged/dropped on the app's icon. You need to have a ! 240: * CFBundleDocumentsType section in your Info.plist to get this message, ! 241: * apparently. ! 242: * ! 243: * Files are added to gArgv, so to the app, they'll look like command line ! 244: * arguments. Previously, apps launched from the finder had nothing but ! 245: * an argv[0]. ! 246: * ! 247: * This message may be received multiple times to open several docs on launch. ! 248: * ! 249: * This message is ignored once the app's mainline has been called. ! 250: */ ! 251: - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename ! 252: { ! 253: const char *temparg; ! 254: size_t arglen; ! 255: char *arg; ! 256: char **newargv; ! 257: ! 258: if (!gFinderLaunch) /* MacOS is passing command line args. */ ! 259: return FALSE; ! 260: ! 261: if (gCalledAppMainline) /* app has started, ignore this document. */ ! 262: return FALSE; ! 263: ! 264: temparg = [filename UTF8String]; ! 265: arglen = SDL_strlen(temparg) + 1; ! 266: arg = (char *) SDL_malloc(arglen); ! 267: if (arg == NULL) ! 268: return FALSE; ! 269: ! 270: newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2)); ! 271: if (newargv == NULL) ! 272: { ! 273: SDL_free(arg); ! 274: return FALSE; ! 275: } ! 276: gArgv = newargv; ! 277: ! 278: SDL_strlcpy(arg, temparg, arglen); ! 279: gArgv[gArgc++] = arg; ! 280: gArgv[gArgc] = NULL; ! 281: return TRUE; ! 282: } ! 283: ! 284: extern char **environ; ! 285: /* Called when the internal event loop has just started running */ ! 286: - (void) applicationDidFinishLaunching: (NSNotification *) note ! 287: { ! 288: int status; ! 289: ! 290: /* Set the working directory to the .app's parent directory */ ! 291: [self setupWorkingDirectory:gFinderLaunch]; ! 292: ! 293: #if SDL_USE_NIB_FILE ! 294: /* Set the main menu to contain the real app name instead of "SDL App" */ ! 295: [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()]; ! 296: #endif ! 297: ! 298: /* Hand off to main application code */ ! 299: gCalledAppMainline = TRUE; ! 300: status = SDL_main_env (gArgc, gArgv, environ); ! 301: ! 302: /* We're done, thank you for playing */ ! 303: exit(status); ! 304: } ! 305: @end ! 306: ! 307: ! 308: @implementation NSString (ReplaceSubString) ! 309: ! 310: - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString ! 311: { ! 312: unsigned int bufferSize; ! 313: unsigned int selfLen = [self length]; ! 314: unsigned int aStringLen = [aString length]; ! 315: unichar *buffer; ! 316: NSRange localRange; ! 317: NSString *result; ! 318: ! 319: bufferSize = selfLen + aStringLen - aRange.length; ! 320: buffer = (unichar *)NSAllocateMemoryPages(bufferSize*sizeof(unichar)); ! 321: ! 322: /* Get first part into buffer */ ! 323: localRange.location = 0; ! 324: localRange.length = aRange.location; ! 325: [self getCharacters:buffer range:localRange]; ! 326: ! 327: /* Get middle part into buffer */ ! 328: localRange.location = 0; ! 329: localRange.length = aStringLen; ! 330: [aString getCharacters:(buffer+aRange.location) range:localRange]; ! 331: ! 332: /* Get last part into buffer */ ! 333: localRange.location = aRange.location + aRange.length; ! 334: localRange.length = selfLen - localRange.location; ! 335: [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange]; ! 336: ! 337: /* Build output string */ ! 338: result = [NSString stringWithCharacters:buffer length:bufferSize]; ! 339: ! 340: NSDeallocateMemoryPages(buffer, bufferSize); ! 341: ! 342: return result; ! 343: } ! 344: ! 345: @end ! 346: ! 347: ! 348: ! 349: #ifdef main ! 350: # undef main ! 351: #endif ! 352: ! 353: ! 354: /* Main entry point to executable - should *not* be SDL_main! */ ! 355: int main (int argc, char **argv) ! 356: { ! 357: /* Copy the arguments into a global variable */ ! 358: /* This is passed if we are launched by double-clicking */ ! 359: if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) { ! 360: gArgv = (char **) SDL_malloc(sizeof (char *) * 2); ! 361: gArgv[0] = argv[0]; ! 362: gArgv[1] = NULL; ! 363: gArgc = 1; ! 364: gFinderLaunch = YES; ! 365: } else { ! 366: int i; ! 367: gArgc = argc; ! 368: gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1)); ! 369: for (i = 0; i <= argc; i++) ! 370: gArgv[i] = argv[i]; ! 371: gFinderLaunch = NO; ! 372: } ! 373: ! 374: #if SDL_USE_NIB_FILE ! 375: NSApplicationMain (argc, argv); ! 376: #else ! 377: CustomApplicationMain (argc, argv); ! 378: #endif ! 379: return 0; ! 380: } ! 381:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.