Xcode/TemplatesForXcodeSnowLeopard/SDL OpenGL Application/SDLMain.m
branchSDL-1.2
changeset 5895 402eac854030
child 12048 eb70ab731d29
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/Xcode/TemplatesForXcodeSnowLeopard/SDL OpenGL Application/SDLMain.m	Sun Sep 11 14:44:37 2011 -0400
     1.3 @@ -0,0 +1,383 @@
     1.4 +/*   SDLMain.m - main entry point for our Cocoa-ized SDL app
     1.5 +       Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
     1.6 +       Non-NIB-Code & other changes: Max Horn <max@quendi.de>
     1.7 +
     1.8 +    Feel free to customize this file to suit your needs
     1.9 +*/
    1.10 +
    1.11 +#include "SDL.h"
    1.12 +#include "SDLMain.h"
    1.13 +#include <sys/param.h> /* for MAXPATHLEN */
    1.14 +#include <unistd.h>
    1.15 +
    1.16 +/* For some reaon, Apple removed setAppleMenu from the headers in 10.4,
    1.17 + but the method still is there and works. To avoid warnings, we declare
    1.18 + it ourselves here. */
    1.19 +@interface NSApplication(SDL_Missing_Methods)
    1.20 +- (void)setAppleMenu:(NSMenu *)menu;
    1.21 +@end
    1.22 +
    1.23 +/* Use this flag to determine whether we use SDLMain.nib or not */
    1.24 +#define		SDL_USE_NIB_FILE	0
    1.25 +
    1.26 +/* Use this flag to determine whether we use CPS (docking) or not */
    1.27 +#define		SDL_USE_CPS		1
    1.28 +#ifdef SDL_USE_CPS
    1.29 +/* Portions of CPS.h */
    1.30 +typedef struct CPSProcessSerNum
    1.31 +{
    1.32 +	UInt32		lo;
    1.33 +	UInt32		hi;
    1.34 +} CPSProcessSerNum;
    1.35 +
    1.36 +extern OSErr	CPSGetCurrentProcess( CPSProcessSerNum *psn);
    1.37 +extern OSErr 	CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
    1.38 +extern OSErr	CPSSetFrontProcess( CPSProcessSerNum *psn);
    1.39 +
    1.40 +#endif /* SDL_USE_CPS */
    1.41 +
    1.42 +static int    gArgc;
    1.43 +static char  **gArgv;
    1.44 +static BOOL   gFinderLaunch;
    1.45 +static BOOL   gCalledAppMainline = FALSE;
    1.46 +
    1.47 +static NSString *getApplicationName(void)
    1.48 +{
    1.49 +    const NSDictionary *dict;
    1.50 +    NSString *appName = 0;
    1.51 +
    1.52 +    /* Determine the application name */
    1.53 +    dict = (const NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
    1.54 +    if (dict)
    1.55 +        appName = [dict objectForKey: @"CFBundleName"];
    1.56 +    
    1.57 +    if (![appName length])
    1.58 +        appName = [[NSProcessInfo processInfo] processName];
    1.59 +
    1.60 +    return appName;
    1.61 +}
    1.62 +
    1.63 +#if SDL_USE_NIB_FILE
    1.64 +/* A helper category for NSString */
    1.65 +@interface NSString (ReplaceSubString)
    1.66 +- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString;
    1.67 +@end
    1.68 +#endif
    1.69 +
    1.70 +@interface SDLApplication : NSApplication
    1.71 +@end
    1.72 +
    1.73 +@implementation SDLApplication
    1.74 +/* Invoked from the Quit menu item */
    1.75 +- (void)terminate:(id)sender
    1.76 +{
    1.77 +    /* Post a SDL_QUIT event */
    1.78 +    SDL_Event event;
    1.79 +    event.type = SDL_QUIT;
    1.80 +    SDL_PushEvent(&event);
    1.81 +}
    1.82 +@end
    1.83 +
    1.84 +/* The main class of the application, the application's delegate */
    1.85 +@implementation SDLMain
    1.86 +
    1.87 +/* Set the working directory to the .app's parent directory */
    1.88 +- (void) setupWorkingDirectory:(BOOL)shouldChdir
    1.89 +{
    1.90 +    if (shouldChdir)
    1.91 +    {
    1.92 +        char parentdir[MAXPATHLEN];
    1.93 +        CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
    1.94 +        CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url);
    1.95 +        if (CFURLGetFileSystemRepresentation(url2, 1, (UInt8 *)parentdir, MAXPATHLEN)) {
    1.96 +            chdir(parentdir);   /* chdir to the binary app's parent */
    1.97 +        }
    1.98 +        CFRelease(url);
    1.99 +        CFRelease(url2);
   1.100 +    }
   1.101 +}
   1.102 +
   1.103 +#if SDL_USE_NIB_FILE
   1.104 +
   1.105 +/* Fix menu to contain the real app name instead of "SDL App" */
   1.106 +- (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName
   1.107 +{
   1.108 +    NSRange aRange;
   1.109 +    NSEnumerator *enumerator;
   1.110 +    NSMenuItem *menuItem;
   1.111 +
   1.112 +    aRange = [[aMenu title] rangeOfString:@"SDL App"];
   1.113 +    if (aRange.length != 0)
   1.114 +        [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]];
   1.115 +
   1.116 +    enumerator = [[aMenu itemArray] objectEnumerator];
   1.117 +    while ((menuItem = [enumerator nextObject]))
   1.118 +    {
   1.119 +        aRange = [[menuItem title] rangeOfString:@"SDL App"];
   1.120 +        if (aRange.length != 0)
   1.121 +            [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]];
   1.122 +        if ([menuItem hasSubmenu])
   1.123 +            [self fixMenu:[menuItem submenu] withAppName:appName];
   1.124 +    }
   1.125 +    [ aMenu sizeToFit ];
   1.126 +}
   1.127 +
   1.128 +#else
   1.129 +
   1.130 +static void setApplicationMenu(void)
   1.131 +{
   1.132 +    /* warning: this code is very odd */
   1.133 +    NSMenu *appleMenu;
   1.134 +    NSMenuItem *menuItem;
   1.135 +    NSString *title;
   1.136 +    NSString *appName;
   1.137 +    
   1.138 +    appName = getApplicationName();
   1.139 +    appleMenu = [[NSMenu alloc] initWithTitle:@""];
   1.140 +    
   1.141 +    /* Add menu items */
   1.142 +    title = [@"About " stringByAppendingString:appName];
   1.143 +    [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
   1.144 +
   1.145 +    [appleMenu addItem:[NSMenuItem separatorItem]];
   1.146 +
   1.147 +    title = [@"Hide " stringByAppendingString:appName];
   1.148 +    [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
   1.149 +
   1.150 +    menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
   1.151 +    [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
   1.152 +
   1.153 +    [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
   1.154 +
   1.155 +    [appleMenu addItem:[NSMenuItem separatorItem]];
   1.156 +
   1.157 +    title = [@"Quit " stringByAppendingString:appName];
   1.158 +    [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
   1.159 +
   1.160 +    
   1.161 +    /* Put menu into the menubar */
   1.162 +    menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
   1.163 +    [menuItem setSubmenu:appleMenu];
   1.164 +    [[NSApp mainMenu] addItem:menuItem];
   1.165 +
   1.166 +    /* Tell the application object that this is now the application menu */
   1.167 +    [NSApp setAppleMenu:appleMenu];
   1.168 +
   1.169 +    /* Finally give up our references to the objects */
   1.170 +    [appleMenu release];
   1.171 +    [menuItem release];
   1.172 +}
   1.173 +
   1.174 +/* Create a window menu */
   1.175 +static void setupWindowMenu(void)
   1.176 +{
   1.177 +    NSMenu      *windowMenu;
   1.178 +    NSMenuItem  *windowMenuItem;
   1.179 +    NSMenuItem  *menuItem;
   1.180 +
   1.181 +    windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
   1.182 +    
   1.183 +    /* "Minimize" item */
   1.184 +    menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
   1.185 +    [windowMenu addItem:menuItem];
   1.186 +    [menuItem release];
   1.187 +    
   1.188 +    /* Put menu into the menubar */
   1.189 +    windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
   1.190 +    [windowMenuItem setSubmenu:windowMenu];
   1.191 +    [[NSApp mainMenu] addItem:windowMenuItem];
   1.192 +    
   1.193 +    /* Tell the application object that this is now the window menu */
   1.194 +    [NSApp setWindowsMenu:windowMenu];
   1.195 +
   1.196 +    /* Finally give up our references to the objects */
   1.197 +    [windowMenu release];
   1.198 +    [windowMenuItem release];
   1.199 +}
   1.200 +
   1.201 +/* Replacement for NSApplicationMain */
   1.202 +static void CustomApplicationMain (int argc, char **argv)
   1.203 +{
   1.204 +    NSAutoreleasePool	*pool = [[NSAutoreleasePool alloc] init];
   1.205 +    SDLMain				*sdlMain;
   1.206 +
   1.207 +    /* Ensure the application object is initialised */
   1.208 +    [SDLApplication sharedApplication];
   1.209 +    
   1.210 +#ifdef SDL_USE_CPS
   1.211 +    {
   1.212 +        CPSProcessSerNum PSN;
   1.213 +        /* Tell the dock about us */
   1.214 +        if (!CPSGetCurrentProcess(&PSN))
   1.215 +            if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
   1.216 +                if (!CPSSetFrontProcess(&PSN))
   1.217 +                    [SDLApplication sharedApplication];
   1.218 +    }
   1.219 +#endif /* SDL_USE_CPS */
   1.220 +
   1.221 +    /* Set up the menubar */
   1.222 +    [NSApp setMainMenu:[[NSMenu alloc] init]];
   1.223 +    setApplicationMenu();
   1.224 +    setupWindowMenu();
   1.225 +
   1.226 +    /* Create SDLMain and make it the app delegate */
   1.227 +    sdlMain = [[SDLMain alloc] init];
   1.228 +    [NSApp setDelegate:sdlMain];
   1.229 +    
   1.230 +    /* Start the main event loop */
   1.231 +    [NSApp run];
   1.232 +    
   1.233 +    [sdlMain release];
   1.234 +    [pool release];
   1.235 +}
   1.236 +
   1.237 +#endif
   1.238 +
   1.239 +
   1.240 +/*
   1.241 + * Catch document open requests...this lets us notice files when the app
   1.242 + *  was launched by double-clicking a document, or when a document was
   1.243 + *  dragged/dropped on the app's icon. You need to have a
   1.244 + *  CFBundleDocumentsType section in your Info.plist to get this message,
   1.245 + *  apparently.
   1.246 + *
   1.247 + * Files are added to gArgv, so to the app, they'll look like command line
   1.248 + *  arguments. Previously, apps launched from the finder had nothing but
   1.249 + *  an argv[0].
   1.250 + *
   1.251 + * This message may be received multiple times to open several docs on launch.
   1.252 + *
   1.253 + * This message is ignored once the app's mainline has been called.
   1.254 + */
   1.255 +- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
   1.256 +{
   1.257 +    const char *temparg;
   1.258 +    size_t arglen;
   1.259 +    char *arg;
   1.260 +    char **newargv;
   1.261 +
   1.262 +    if (!gFinderLaunch)  /* MacOS is passing command line args. */
   1.263 +        return FALSE;
   1.264 +
   1.265 +    if (gCalledAppMainline)  /* app has started, ignore this document. */
   1.266 +        return FALSE;
   1.267 +
   1.268 +    temparg = [filename UTF8String];
   1.269 +    arglen = SDL_strlen(temparg) + 1;
   1.270 +    arg = (char *) SDL_malloc(arglen);
   1.271 +    if (arg == NULL)
   1.272 +        return FALSE;
   1.273 +
   1.274 +    newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2));
   1.275 +    if (newargv == NULL)
   1.276 +    {
   1.277 +        SDL_free(arg);
   1.278 +        return FALSE;
   1.279 +    }
   1.280 +    gArgv = newargv;
   1.281 +
   1.282 +    SDL_strlcpy(arg, temparg, arglen);
   1.283 +    gArgv[gArgc++] = arg;
   1.284 +    gArgv[gArgc] = NULL;
   1.285 +    return TRUE;
   1.286 +}
   1.287 +
   1.288 +
   1.289 +/* Called when the internal event loop has just started running */
   1.290 +- (void) applicationDidFinishLaunching: (NSNotification *) note
   1.291 +{
   1.292 +    int status;
   1.293 +
   1.294 +    /* Set the working directory to the .app's parent directory */
   1.295 +    [self setupWorkingDirectory:gFinderLaunch];
   1.296 +
   1.297 +#if SDL_USE_NIB_FILE
   1.298 +    /* Set the main menu to contain the real app name instead of "SDL App" */
   1.299 +    [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()];
   1.300 +#endif
   1.301 +
   1.302 +    /* Hand off to main application code */
   1.303 +    gCalledAppMainline = TRUE;
   1.304 +    status = SDL_main (gArgc, gArgv);
   1.305 +
   1.306 +    /* We're done, thank you for playing */
   1.307 +    exit(status);
   1.308 +}
   1.309 +@end
   1.310 +
   1.311 +
   1.312 +@implementation NSString (ReplaceSubString)
   1.313 +
   1.314 +- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString
   1.315 +{
   1.316 +    unsigned int bufferSize;
   1.317 +    unsigned int selfLen = [self length];
   1.318 +    unsigned int aStringLen = [aString length];
   1.319 +    unichar *buffer;
   1.320 +    NSRange localRange;
   1.321 +    NSString *result;
   1.322 +
   1.323 +    bufferSize = selfLen + aStringLen - aRange.length;
   1.324 +    buffer = (unichar *)NSAllocateMemoryPages(bufferSize*sizeof(unichar));
   1.325 +    
   1.326 +    /* Get first part into buffer */
   1.327 +    localRange.location = 0;
   1.328 +    localRange.length = aRange.location;
   1.329 +    [self getCharacters:buffer range:localRange];
   1.330 +    
   1.331 +    /* Get middle part into buffer */
   1.332 +    localRange.location = 0;
   1.333 +    localRange.length = aStringLen;
   1.334 +    [aString getCharacters:(buffer+aRange.location) range:localRange];
   1.335 +     
   1.336 +    /* Get last part into buffer */
   1.337 +    localRange.location = aRange.location + aRange.length;
   1.338 +    localRange.length = selfLen - localRange.location;
   1.339 +    [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange];
   1.340 +    
   1.341 +    /* Build output string */
   1.342 +    result = [NSString stringWithCharacters:buffer length:bufferSize];
   1.343 +    
   1.344 +    NSDeallocateMemoryPages(buffer, bufferSize);
   1.345 +    
   1.346 +    return result;
   1.347 +}
   1.348 +
   1.349 +@end
   1.350 +
   1.351 +
   1.352 +
   1.353 +#ifdef main
   1.354 +#  undef main
   1.355 +#endif
   1.356 +
   1.357 +
   1.358 +/* Main entry point to executable - should *not* be SDL_main! */
   1.359 +int main (int argc, char **argv)
   1.360 +{
   1.361 +    /* Copy the arguments into a global variable */
   1.362 +    /* This is passed if we are launched by double-clicking */
   1.363 +    if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) {
   1.364 +        gArgv = (char **) SDL_malloc(sizeof (char *) * 2);
   1.365 +        gArgv[0] = argv[0];
   1.366 +        gArgv[1] = NULL;
   1.367 +        gArgc = 1;
   1.368 +        gFinderLaunch = YES;
   1.369 +    } else {
   1.370 +        int i;
   1.371 +        gArgc = argc;
   1.372 +        gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1));
   1.373 +        for (i = 0; i <= argc; i++)
   1.374 +            gArgv[i] = argv[i];
   1.375 +        gFinderLaunch = NO;
   1.376 +    }
   1.377 +
   1.378 +#if SDL_USE_NIB_FILE
   1.379 +    [SDLApplication poseAsClass:[NSApplication class]];
   1.380 +    NSApplicationMain (argc, argv);
   1.381 +#else
   1.382 +    CustomApplicationMain (argc, argv);
   1.383 +#endif
   1.384 +    return 0;
   1.385 +}
   1.386 +