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