|
|
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:
1.1.1.2 ! root 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
1.1 root 19:
20: /* Use this flag to determine whether we use SDLMain.nib or not */
21: #define SDL_USE_NIB_FILE 0
22:
1.1.1.2 ! root 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 */
1.1 root 38:
39: static int gArgc;
40: static char **gArgv;
41: static BOOL gFinderLaunch;
1.1.1.2 ! root 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: }
1.1 root 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:
1.1.1.2 ! root 67: @interface NSApplication (SDLApplication)
1.1 root 68: @end
69:
1.1.1.2 ! root 70: @implementation NSApplication (SDLApplication)
1.1 root 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: {
1.1.1.2 ! root 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);
1.1 root 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:
1.1.1.2 ! root 126: static void setApplicationMenu(void)
1.1 root 127: {
128: /* warning: this code is very odd */
129: NSMenu *appleMenu;
1.1.1.2 ! root 130: NSMenuItem *menuItem;
! 131: NSString *title;
! 132: NSString *appName;
! 133:
! 134: appName = getApplicationName();
1.1 root 135: appleMenu = [[NSMenu alloc] initWithTitle:@""];
136:
1.1.1.2 ! root 137: /* Add menu items */
! 138: title = [@"About " stringByAppendingString:appName];
! 139: [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
! 140:
! 141: [appleMenu addItem:[NSMenuItem separatorItem]];
1.1 root 142:
1.1.1.2 ! root 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 */
1.1 root 166: [appleMenu release];
1.1.1.2 ! root 167: [menuItem release];
1.1 root 168: }
169:
170: /* Create a window menu */
1.1.1.2 ! root 171: static void setupWindowMenu(void)
1.1 root 172: {
1.1.1.2 ! root 173: NSMenu *windowMenu;
! 174: NSMenuItem *windowMenuItem;
! 175: NSMenuItem *menuItem;
1.1 root 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 */
1.1.1.2 ! root 198: static void CustomApplicationMain (int argc, char **argv)
1.1 root 199: {
200: NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
201: SDLMain *sdlMain;
202:
203: /* Ensure the application object is initialised */
1.1.1.2 ! root 204: [NSApplication sharedApplication];
1.1 root 205:
1.1.1.2 ! root 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:
1.1 root 217: /* Set up the menubar */
218: [NSApp setMainMenu:[[NSMenu alloc] init]];
1.1.1.2 ! root 219: setApplicationMenu();
1.1 root 220: setupWindowMenu();
1.1.1.2 ! root 221:
1.1 root 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:
1.1.1.2 ! root 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;
1.1 root 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" */
1.1.1.2 ! root 295: [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()];
1.1 root 296: #endif
297:
298: /* Hand off to main application code */
1.1.1.2 ! root 299: gCalledAppMainline = TRUE;
1.1 root 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;
1.1.1.2 ! root 320: buffer = (unichar *)NSAllocateMemoryPages(bufferSize*sizeof(unichar));
1.1 root 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 ) {
1.1.1.2 ! root 360: gArgv = (char **) SDL_malloc(sizeof (char *) * 2);
! 361: gArgv[0] = argv[0];
! 362: gArgv[1] = NULL;
1.1 root 363: gArgc = 1;
1.1.1.2 ! root 364: gFinderLaunch = YES;
1.1 root 365: } else {
1.1.1.2 ! root 366: int i;
1.1 root 367: gArgc = argc;
1.1.1.2 ! root 368: gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1));
! 369: for (i = 0; i <= argc; i++)
! 370: gArgv[i] = argv[i];
! 371: gFinderLaunch = NO;
1.1 root 372: }
373:
374: #if SDL_USE_NIB_FILE
375: NSApplicationMain (argc, argv);
376: #else
377: CustomApplicationMain (argc, argv);
378: #endif
379: return 0;
380: }
1.1.1.2 ! root 381:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.