SDLMain.m

Go to the documentation of this file.
00001 /*   SDLMain.m - main entry point for our Cocoa-ized SDL app
00002        Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
00003        Non-NIB-Code & other changes: Max Horn <max@quendi.de>
00004 
00005     Feel free to customize this file to suit your needs
00006 */
00007 
00008 #import "SDL.h"
00009 #import "SDLMain.h"
00010 #import <sys/param.h> /* for MAXPATHLEN */
00011 #import <unistd.h>
00012 
00013 /* For some reaon, Apple removed setAppleMenu from the headers in 10.4,
00014  but the method still is there and works. To avoid warnings, we declare
00015  it ourselves here. */
00016 @interface NSApplication(SDL_Missing_Methods)
00017 - (void)setAppleMenu:(NSMenu *)menu;
00018 @end
00019 
00020 /* Use this flag to determine whether we use SDLMain.nib or not */
00021 #define         SDL_USE_NIB_FILE        0
00022 
00023 /* Use this flag to determine whether we use CPS (docking) or not */
00024 #define         SDL_USE_CPS             1
00025 #ifdef SDL_USE_CPS
00026 /* Portions of CPS.h */
00027 typedef struct CPSProcessSerNum
00028 {
00029         UInt32          lo;
00030         UInt32          hi;
00031 } CPSProcessSerNum;
00032 
00033 extern OSErr    CPSGetCurrentProcess( CPSProcessSerNum *psn);
00034 extern OSErr    CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
00035 extern OSErr    CPSSetFrontProcess( CPSProcessSerNum *psn);
00036 
00037 #endif /* SDL_USE_CPS */
00038 
00039 static int    gArgc;
00040 static char  **gArgv;
00041 static BOOL   gFinderLaunch;
00042 static BOOL   gCalledAppMainline = FALSE;
00043 
00044 static NSString *getApplicationName(void)
00045 {
00046     NSDictionary *dict;
00047     NSString *appName = 0;
00048 
00049     /* Determine the application name */
00050     dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
00051     if (dict)
00052         appName = [dict objectForKey: @"CFBundleName"];
00053     
00054     if (![appName length])
00055         appName = [[NSProcessInfo processInfo] processName];
00056 
00057     return appName;
00058 }
00059 
00060 #if SDL_USE_NIB_FILE
00061 /* A helper category for NSString */
00062 @interface NSString (ReplaceSubString)
00063 - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString;
00064 @end
00065 #endif
00066 
00067 @interface SDLApplication : NSApplication
00068 @end
00069 
00070 @implementation SDLApplication
00071 /* Invoked from the Quit menu item */
00072 - (void)terminate:(id)sender
00073 {
00074     /* Post a SDL_QUIT event */
00075     SDL_Event event;
00076     event.type = SDL_QUIT;
00077     SDL_PushEvent(&event);
00078 }
00079 @end
00080 
00081 /* The main class of the application, the application's delegate */
00082 @implementation SDLMain
00083 
00084 /* Set the working directory to the .app's parent directory */
00085 - (void) setupWorkingDirectory:(BOOL)shouldChdir
00086 {
00087     if (shouldChdir)
00088     {
00089         char parentdir;
00090                 CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
00091                 CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url);
00092                 if (CFURLGetFileSystemRepresentation(url2, true, (UInt8 *)parentdir, MAXPATHLEN)) {
00093                 assert ( chdir (parentdir) == 0 );   /* chdir to the binary app's parent */
00094                 }
00095                 CFRelease(url);
00096                 CFRelease(url2);
00097         }
00098 
00099 }
00100 
00101 #if SDL_USE_NIB_FILE
00102 
00103 /* Fix menu to contain the real app name instead of "SDL App" */
00104 - (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName
00105 {
00106     NSRange aRange;
00107     NSEnumerator *enumerator;
00108     NSMenuItem *menuItem;
00109 
00110     aRange = [[aMenu title] rangeOfString:@"SDL App"];
00111     if (aRange.length != 0)
00112         [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]];
00113 
00114     enumerator = [[aMenu itemArray] objectEnumerator];
00115     while ((menuItem = [enumerator nextObject]))
00116     {
00117         aRange = [[menuItem title] rangeOfString:@"SDL App"];
00118         if (aRange.length != 0)
00119             [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]];
00120         if ([menuItem hasSubmenu])
00121             [self fixMenu:[menuItem submenu] withAppName:appName];
00122     }
00123     [ aMenu sizeToFit ];
00124 }
00125 
00126 #else
00127 
00128 static void setApplicationMenu(void)
00129 {
00130     /* warning: this code is very odd */
00131     NSMenu *appleMenu;
00132     NSMenuItem *menuItem;
00133     NSString *title;
00134     NSString *appName;
00135     
00136     appName = getApplicationName();
00137     appleMenu = [[NSMenu alloc] initWithTitle:@""];
00138     
00139     /* Add menu items */
00140     title = [@"About " stringByAppendingString:appName];
00141     [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
00142 
00143     [appleMenu addItem:[NSMenuItem separatorItem]];
00144 
00145     title = [@"Hide " stringByAppendingString:appName];
00146     [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
00147 
00148     menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
00149     [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
00150 
00151     [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
00152 
00153     [appleMenu addItem:[NSMenuItem separatorItem]];
00154 
00155     title = [@"Quit " stringByAppendingString:appName];
00156     [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
00157 
00158     
00159     /* Put menu into the menubar */
00160     menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
00161     [menuItem setSubmenu:appleMenu];
00162     [[NSApp mainMenu] addItem:menuItem];
00163 
00164     /* Tell the application object that this is now the application menu */
00165     [NSApp setAppleMenu:appleMenu];
00166 
00167     /* Finally give up our references to the objects */
00168     [appleMenu release];
00169     [menuItem release];
00170 }
00171 
00172 /* Create a window menu */
00173 static void setupWindowMenu(void)
00174 {
00175     NSMenu      *windowMenu;
00176     NSMenuItem  *windowMenuItem;
00177     NSMenuItem  *menuItem;
00178 
00179     windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
00180     
00181     /* "Minimize" item */
00182     menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
00183     [windowMenu addItem:menuItem];
00184     [menuItem release];
00185     
00186     /* Put menu into the menubar */
00187     windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
00188     [windowMenuItem setSubmenu:windowMenu];
00189     [[NSApp mainMenu] addItem:windowMenuItem];
00190     
00191     /* Tell the application object that this is now the window menu */
00192     [NSApp setWindowsMenu:windowMenu];
00193 
00194     /* Finally give up our references to the objects */
00195     [windowMenu release];
00196     [windowMenuItem release];
00197 }
00198 
00199 /* Replacement for NSApplicationMain */
00200 static void CustomApplicationMain (int argc, char **argv)
00201 {
00202     NSAutoreleasePool   *pool = [[NSAutoreleasePool alloc] init];
00203     SDLMain                             *sdlMain;
00204 
00205     /* Ensure the application object is initialised */
00206     [SDLApplication sharedApplication];
00207     
00208 #ifdef SDL_USE_CPS
00209     {
00210         CPSProcessSerNum PSN;
00211         /* Tell the dock about us */
00212         if (!CPSGetCurrentProcess(&PSN))
00213             if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
00214                 if (!CPSSetFrontProcess(&PSN))
00215                     [SDLApplication sharedApplication];
00216     }
00217 #endif /* SDL_USE_CPS */
00218 
00219     /* Set up the menubar */
00220     [NSApp setMainMenu:[[NSMenu alloc] init]];
00221     setApplicationMenu();
00222     setupWindowMenu();
00223 
00224     /* Create SDLMain and make it the app delegate */
00225     sdlMain = [[SDLMain alloc] init];
00226     [NSApp setDelegate:sdlMain];
00227     
00228     /* Start the main event loop */
00229     [NSApp run];
00230     
00231     [sdlMain release];
00232     [pool release];
00233 }
00234 
00235 #endif
00236 
00237 
00238 /*
00239  * Catch document open requests...this lets us notice files when the app
00240  *  was launched by double-clicking a document, or when a document was
00241  *  dragged/dropped on the app's icon. You need to have a
00242  *  CFBundleDocumentsType section in your Info.plist to get this message,
00243  *  apparently.
00244  *
00245  * Files are added to gArgv, so to the app, they'll look like command line
00246  *  arguments. Previously, apps launched from the finder had nothing but
00247  *  an argv[0].
00248  *
00249  * This message may be received multiple times to open several docs on launch.
00250  *
00251  * This message is ignored once the app's mainline has been called.
00252  */
00253 - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
00254 {
00255     const char *temparg;
00256     size_t arglen;
00257     char *arg;
00258     char **newargv;
00259 
00260     if (!gFinderLaunch)  /* MacOS is passing command line args. */
00261         return FALSE;
00262 
00263     if (gCalledAppMainline)  /* app has started, ignore this document. */
00264         return FALSE;
00265 
00266     temparg = [filename UTF8String];
00267     arglen = SDL_strlen(temparg) + 1;
00268     arg = (char *) SDL_malloc(arglen);
00269     if (arg == NULL)
00270         return FALSE;
00271 
00272     newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2));
00273     if (newargv == NULL)
00274     {
00275         SDL_free(arg);
00276         return FALSE;
00277     }
00278     gArgv = newargv;
00279 
00280     SDL_strlcpy(arg, temparg, arglen);
00281     gArgv = arg;
00282     gArgv = NULL;
00283     return TRUE;
00284 }
00285 
00286 
00287 /* Called when the internal event loop has just started running */
00288 - (void) applicationDidFinishLaunching: (NSNotification *) note
00289 {
00290     int status;
00291 
00292     /* Set the working directory to the .app's parent directory */
00293     [self setupWorkingDirectory:gFinderLaunch];
00294 
00295 #if SDL_USE_NIB_FILE
00296     /* Set the main menu to contain the real app name instead of "SDL App" */
00297     [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()];
00298 #endif
00299 
00300     /* Hand off to main application code */
00301     gCalledAppMainline = TRUE;
00302     status = SDL_main (gArgc, gArgv);
00303 
00304     /* We're done, thank you for playing */
00305     exit(status);
00306 }
00307 @end
00308 
00309 
00310 @implementation NSString (ReplaceSubString)
00311 
00312 - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString
00313 {
00314     unsigned int bufferSize;
00315     unsigned int selfLen = [self length];
00316     unsigned int aStringLen = [aString length];
00317     unichar *buffer;
00318     NSRange localRange;
00319     NSString *result;
00320 
00321     bufferSize = selfLen + aStringLen - aRange.length;
00322     buffer = NSAllocateMemoryPages(bufferSize*sizeof(unichar));
00323     
00324     /* Get first part into buffer */
00325     localRange.location = 0;
00326     localRange.length = aRange.location;
00327     [self getCharacters:buffer range:localRange];
00328     
00329     /* Get middle part into buffer */
00330     localRange.location = 0;
00331     localRange.length = aStringLen;
00332     [aString getCharacters:(buffer+aRange.location) range:localRange];
00333      
00334     /* Get last part into buffer */
00335     localRange.location = aRange.location + aRange.length;
00336     localRange.length = selfLen - localRange.location;
00337     [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange];
00338     
00339     /* Build output string */
00340     result = [NSString stringWithCharacters:buffer length:bufferSize];
00341     
00342     NSDeallocateMemoryPages(buffer, bufferSize);
00343     
00344     return result;
00345 }
00346 
00347 @end
00348 
00349 
00350 
00351 #ifdef main
00352 #  undef main
00353 #endif
00354 
00355 
00356 /* Main entry point to executable - should *not* be SDL_main! */
00357 int main (int argc, char **argv)
00358 {
00359     /* Copy the arguments into a global variable */
00360     /* This is passed if we are launched by double-clicking */
00361     if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) {
00362         gArgv = (char **) SDL_malloc(sizeof (char *) * 2);
00363         gArgv = argv;
00364         gArgv = NULL;
00365         gArgc = 1;
00366         gFinderLaunch = YES;
00367     } else {
00368         int i;
00369         gArgc = argc;
00370         gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1));
00371         for (i = 0; i <= argc; i++)
00372             gArgv[i] = argv[i];
00373         gFinderLaunch = NO;
00374     }
00375 
00376 #if SDL_USE_NIB_FILE
00377     [SDLApplication poseAsClass:[NSApplication class]];
00378     NSApplicationMain (argc, argv);
00379 #else
00380     CustomApplicationMain (argc, argv);
00381 #endif
00382     return 0;
00383 }

Generated on Fri Jul 27 22:27:35 2007 for pentagram by  doxygen 1.4.7