123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398 |
- /* SDLMain.m - main entry point for our Cocoa-ized SDL app
- Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
- Non-NIB-Code & other changes: Max Horn <max@quendi.de>
- Feel free to customize this file to suit your needs
- */
- #import "SDL.h"
- #import "SDLMain_SDL12.h"
- #import <sys/param.h> /* for MAXPATHLEN */
- #import <unistd.h>
- /* For some reaon, Apple removed setAppleMenu from the headers in 10.4,
- but the method still is there and works. To avoid warnings, we declare
- it ourselves here. */
- @interface NSApplication(SDL_Missing_Methods)
- - (void)setAppleMenu:(NSMenu *)menu;
- @end
- /* Use this flag to determine whether we use SDLMain.nib or not */
- #define SDL_USE_NIB_FILE 0
- /* Use this flag to determine whether we use CPS (docking) or not */
- #define SDL_USE_CPS 1
- #ifdef SDL_USE_CPS
- /* Portions of CPS.h */
- typedef struct CPSProcessSerNum
- {
- UInt32 lo;
- UInt32 hi;
- } CPSProcessSerNum;
- extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn);
- extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
- extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn);
- #endif /* SDL_USE_CPS */
- static int gArgc;
- static char **gArgv;
- static BOOL gFinderLaunch;
- static BOOL gCalledAppMainline = FALSE;
- static NSString *getApplicationName(void)
- {
- NSDictionary *dict;
- NSString *appName = 0;
- /* Determine the application name */
- dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
- if (dict)
- appName = [dict objectForKey: @"CFBundleName"];
-
- if (![appName length])
- appName = [[NSProcessInfo processInfo] processName];
- return appName;
- }
- #if SDL_USE_NIB_FILE
- /* A helper category for NSString */
- @interface NSString (ReplaceSubString)
- - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString;
- @end
- #endif
- @interface SDLApplication : NSApplication
- @end
- void PAL_Shutdown();
- @implementation SDLApplication
- /* Invoked from the Quit menu item */
- - (void)terminate:(id)sender
- {
- /* Post a SDL_QUIT event */
- PAL_Shutdown();
- exit(0);
- }
- @end
- /* The main class of the application, the application's delegate */
- @implementation SDLMain
- /* Set the working directory to the .app's parent directory */
- - (void) setupWorkingDirectory:(BOOL)shouldChdir
- {
- if (shouldChdir)
- {
- char parentdir[MAXPATHLEN];
- CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
- CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url);
- if (CFURLGetFileSystemRepresentation(url2, true, (UInt8 *)parentdir, MAXPATHLEN)) {
- assert ( chdir (parentdir) == 0 ); /* chdir to the binary app's parent */
- }
- CFRelease(url);
- CFRelease(url2);
- }
- }
- #if SDL_USE_NIB_FILE
- /* Fix menu to contain the real app name instead of "SDL App" */
- - (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName
- {
- NSRange aRange;
- NSEnumerator *enumerator;
- NSMenuItem *menuItem;
- aRange = [[aMenu title] rangeOfString:@"SDL App"];
- if (aRange.length != 0)
- [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]];
- enumerator = [[aMenu itemArray] objectEnumerator];
- while ((menuItem = [enumerator nextObject]))
- {
- aRange = [[menuItem title] rangeOfString:@"SDL App"];
- if (aRange.length != 0)
- [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]];
- if ([menuItem hasSubmenu])
- [self fixMenu:[menuItem submenu] withAppName:appName];
- }
- [ aMenu sizeToFit ];
- }
- #else
- static void setApplicationMenu(void)
- {
- /* warning: this code is very odd */
- NSMenu *appleMenu;
- NSMenuItem *menuItem;
- NSString *title;
- NSString *appName;
-
- appName = getApplicationName();
- appleMenu = [[NSMenu alloc] initWithTitle:@""];
-
- /* Add menu items */
- title = [@"About " stringByAppendingString:appName];
- [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
- [appleMenu addItem:[NSMenuItem separatorItem]];
- title = [@"Hide " stringByAppendingString:appName];
- [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
- menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
- [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
- [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
- [appleMenu addItem:[NSMenuItem separatorItem]];
- title = [@"Quit " stringByAppendingString:appName];
- [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
-
- /* Put menu into the menubar */
- menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
- [menuItem setSubmenu:appleMenu];
- [[NSApp mainMenu] addItem:menuItem];
- /* Tell the application object that this is now the application menu */
- [NSApp setAppleMenu:appleMenu];
- /* Finally give up our references to the objects */
- [appleMenu release];
- [menuItem release];
- }
- /* Create a window menu */
- static void setupWindowMenu(void)
- {
- NSMenu *windowMenu;
- NSMenuItem *windowMenuItem;
- NSMenuItem *menuItem;
- windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
-
- /* "Minimize" item */
- menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
- [windowMenu addItem:menuItem];
- [menuItem release];
-
- /* Put menu into the menubar */
- windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
- [windowMenuItem setSubmenu:windowMenu];
- [[NSApp mainMenu] addItem:windowMenuItem];
-
- /* Tell the application object that this is now the window menu */
- [NSApp setWindowsMenu:windowMenu];
- /* Finally give up our references to the objects */
- [windowMenu release];
- [windowMenuItem release];
- }
- /* Replacement for NSApplicationMain */
- static void CustomApplicationMain (int argc, char **argv)
- {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- SDLMain *sdlMain;
- /* Ensure the application object is initialised */
- [SDLApplication sharedApplication];
-
- #ifdef SDL_USE_CPS
- {
- CPSProcessSerNum PSN;
- /* Tell the dock about us */
- if (!CPSGetCurrentProcess(&PSN))
- if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
- if (!CPSSetFrontProcess(&PSN))
- [SDLApplication sharedApplication];
- }
- #endif /* SDL_USE_CPS */
- /* Set up the menubar */
- [NSApp setMainMenu:[[NSMenu alloc] init]];
- setApplicationMenu();
- setupWindowMenu();
- /* Create SDLMain and make it the app delegate */
- sdlMain = [[SDLMain alloc] init];
- [NSApp setDelegate:sdlMain];
-
- /* Start the main event loop */
- [NSApp run];
-
- [sdlMain release];
- [pool release];
- }
- #endif
- /*
- * Catch document open requests...this lets us notice files when the app
- * was launched by double-clicking a document, or when a document was
- * dragged/dropped on the app's icon. You need to have a
- * CFBundleDocumentsType section in your Info.plist to get this message,
- * apparently.
- *
- * Files are added to gArgv, so to the app, they'll look like command line
- * arguments. Previously, apps launched from the finder had nothing but
- * an argv[0].
- *
- * This message may be received multiple times to open several docs on launch.
- *
- * This message is ignored once the app's mainline has been called.
- */
- - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
- {
- const char *temparg;
- size_t arglen;
- char *arg;
- char **newargv;
- if (!gFinderLaunch) /* MacOS is passing command line args. */
- return FALSE;
- if (gCalledAppMainline) /* app has started, ignore this document. */
- return FALSE;
- temparg = [filename UTF8String];
- arglen = SDL_strlen(temparg) + 1;
- arg = (char *) SDL_malloc(arglen);
- if (arg == NULL)
- return FALSE;
- newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2));
- if (newargv == NULL)
- {
- SDL_free(arg);
- return FALSE;
- }
- gArgv = newargv;
- SDL_strlcpy(arg, temparg, arglen);
- gArgv[gArgc++] = arg;
- gArgv[gArgc] = NULL;
- return TRUE;
- }
- /* Called when the internal event loop has just started running */
- - (void) applicationDidFinishLaunching: (NSNotification *) note
- {
- int status;
- /* Set the working directory to the .app's parent directory */
- [self setupWorkingDirectory:gFinderLaunch];
- #if SDL_USE_NIB_FILE
- /* Set the main menu to contain the real app name instead of "SDL App" */
- [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()];
- #endif
- /* Hand off to main application code */
- gCalledAppMainline = TRUE;
- status = SDL_main (gArgc, gArgv);
- /* We're done, thank you for playing */
- exit(status);
- }
- @end
- @implementation NSString (ReplaceSubString)
- - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString
- {
- unsigned int bufferSize;
- unsigned int selfLen = [self length];
- unsigned int aStringLen = [aString length];
- unichar *buffer;
- NSRange localRange;
- NSString *result;
- bufferSize = selfLen + aStringLen - aRange.length;
- buffer = NSAllocateMemoryPages(bufferSize*sizeof(unichar));
-
- /* Get first part into buffer */
- localRange.location = 0;
- localRange.length = aRange.location;
- [self getCharacters:buffer range:localRange];
-
- /* Get middle part into buffer */
- localRange.location = 0;
- localRange.length = aStringLen;
- [aString getCharacters:(buffer+aRange.location) range:localRange];
-
- /* Get last part into buffer */
- localRange.location = aRange.location + aRange.length;
- localRange.length = selfLen - localRange.location;
- [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange];
-
- /* Build output string */
- result = [NSString stringWithCharacters:buffer length:bufferSize];
-
- NSDeallocateMemoryPages(buffer, bufferSize);
-
- return result;
- }
- @end
- #ifdef main
- # undef main
- #endif
- /* Main entry point to executable - should *not* be SDL_main! */
- int main (int argc, char **argv)
- {
- /* Copy the arguments into a global variable */
- /* This is passed if we are launched by double-clicking */
- if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) {
- gArgv = (char **) SDL_malloc(sizeof (char *) * 2);
- gArgv[0] = argv[0];
- gArgv[1] = NULL;
- gArgc = 1;
- gFinderLaunch = YES;
- } else {
- int i;
- gArgc = argc;
- gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1));
- for (i = 0; i <= argc; i++)
- gArgv[i] = argv[i];
- gFinderLaunch = NO;
- }
- // set current working directory to containing path
- // required for OSX Mavericks
- NSBundle *main_bundle = [NSBundle mainBundle];
- NSString *bundle_path = [main_bundle bundlePath];
- NSString *to_dir = [bundle_path stringByAppendingString:@"/../"];
- NSFileManager *fm = [NSFileManager defaultManager];
- [fm changeCurrentDirectoryPath: to_dir];
- [fm release];
- [to_dir release];
- [bundle_path release];
- [main_bundle release];
- #if SDL_USE_NIB_FILE
- [SDLApplication poseAsClass:[NSApplication class]];
- NSApplicationMain (argc, argv);
- #else
- CustomApplicationMain (argc, argv);
- #endif
- return 0;
- }
|