// Emacs style mode select -*- Objective-C -*- //----------------------------------------------------------------------------- // // Copyright(C) 2012-2013 Ioan Chera // // *** Based on SDLMain.m code by Darrell Walisser, Max Horn et al. *** // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //-------------------------------------------------------------------------- // // DESCRIPTION: // Main entry point for Cocoa Eternity SDL app // //----------------------------------------------------------------------------- // SDLMain.m - main entry point for our Cocoa-ized SDL app // Initial Version: Darrell Walisser // Non-NIB-Code & other changes: Max Horn // Feel free to customize this file to suit your needs #include "SDL.h" // IOANCH 20130129: changed to SDL/SDL.h. #import "SDLMain.h" // IOANCH 20130129: use #import #include // for MAXPATHLEN #include // // NSApplication(SDL_Missing_Methods) // // 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 // // CPSProcessSerNum // 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; // // getApplicationName // static NSString *getApplicationName(void) { const NSDictionary *dict; NSString *appName = 0; // Determine the application name dict = (const NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()); if (dict) appName = [dict objectForKey: @"CFBundleName"]; if (![appName length]) appName = [[NSProcessInfo processInfo] processName]; return appName; } #if SDL_USE_NIB_FILE // // NSString (ReplaceSubString) // // A helper category for NSString // @interface NSString (ReplaceSubString) - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString; @end #endif // // NSApplication (SDLApplication) // @interface NSApplication (SDLApplication) @end // // NSApplication (SDLApplication) // @implementation NSApplication (SDLApplication) // // terminate: // // Invoked from the Quit menu item // //- (void)terminate:(id)sender //{ // /* Post a SDL_QUIT event */ // SDL_Event event; // event.type = SDL_QUIT; // SDL_PushEvent(&event); //} // // IOANCH 20130527: commented this out ^ // @end // // SDLMain // // The main class of the application, the application's delegate // @implementation SDLMain // // setupWorkingDirectory: // // 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, 1, (UInt8 *)parentdir, MAXPATHLEN)) { chdir(parentdir); // chdir to the binary app's parent } CFRelease(url); CFRelease(url2); } } #if SDL_USE_NIB_FILE // // fixMenu:withAppName: // // 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]; } } #else // // setApplicationMenu // 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]; } // // setupWindowMenu // // 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]; } // // CustomApplicationMain // // Replacement for NSApplicationMain // static void CustomApplicationMain (int argc, char **argv) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; SDLMain *sdlMain; // Ensure the application object is initialised [NSApplication 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)) [NSApplication 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 // // application:openFile: // // 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; } // // applicationDidFinishLaunching: // // 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 // // NSString (ReplaceSubString) // @implementation NSString (ReplaceSubString) // // stringByReplacingRange:with: // - (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 = (unichar *)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 // // 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; } #if SDL_USE_NIB_FILE NSApplicationMain (argc, argv); #else CustomApplicationMain (argc, argv); #endif return 0; } // EOF