Mercurial > sdl-ios-xcode
comparison Xcode/TemplatesForXcode/SDL Cocoa Application/SDLMain.m @ 2207:d63e9f5944ae
Unpacked project archives to get individual file history in subversion
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Sat, 21 Jul 2007 17:09:01 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
2206:ca7d2227d630 | 2207:d63e9f5944ae |
---|---|
1 /* SDLMain.m - main entry point for our Cocoa-ized SDL app | |
2 Initial Version: Darrell Walisser <dwaliss1@purdue.edu> | |
3 Non-NIB-Code & other changes: Max Horn <max@quendi.de> | |
4 | |
5 Feel free to customize this file to suit your needs | |
6 */ | |
7 | |
8 #import "SDL.h" | |
9 #import "SDLMain.h" | |
10 #import <sys/param.h> /* for MAXPATHLEN */ | |
11 #import <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 1 | |
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 NSDictionary *dict; | |
47 NSString *appName = 0; | |
48 | |
49 /* Determine the application name */ | |
50 dict = (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 SDLApplication : NSApplication | |
68 @end | |
69 | |
70 @implementation 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 - (IBAction)prefsMenu:(id)sender | |
85 { | |
86 printf ("prefs menu\n"); | |
87 } | |
88 | |
89 - (IBAction)newGame:(id)sender | |
90 { | |
91 printf ("new game\n"); | |
92 | |
93 NSRunAlertPanel (@"Get ready to blow up some... stuff!", | |
94 @"Click OK to begin total carnage. Click Cancel to prevent total carnage.", @"OK", @"Cancel", nil); | |
95 } | |
96 | |
97 - (IBAction)openGame:(id)sender | |
98 { | |
99 NSString *path = nil; | |
100 NSOpenPanel *openPanel = [ NSOpenPanel openPanel ]; | |
101 | |
102 if ( [ openPanel runModalForDirectory:nil | |
103 file:@"SavedGame" types:nil ] ) { | |
104 | |
105 path = [ [ openPanel filenames ] objectAtIndex:0 ]; | |
106 } | |
107 | |
108 printf ("open game: %s\n", [ path cString ]); | |
109 } | |
110 | |
111 - (IBAction)saveGame:(id)sender | |
112 { | |
113 NSString *path = nil; | |
114 NSSavePanel *savePanel = [ NSSavePanel savePanel ]; | |
115 | |
116 if ( [ savePanel runModalForDirectory:nil | |
117 file:@"SaveGameFile" ] ) { | |
118 | |
119 path = [ savePanel filename ]; | |
120 } | |
121 | |
122 printf ("save game: %s\n", [ path cString ]); | |
123 } | |
124 | |
125 - (IBAction)saveGameAs:(id)sender | |
126 { | |
127 printf ("save game as\n"); | |
128 } | |
129 | |
130 - (IBAction)help:(id)sender | |
131 { | |
132 NSRunAlertPanel (@"Oh help, where have ye gone?", | |
133 @"Sorry, there is no help available.\n\nThis message brought to you by We Don't Document, Inc.\n\n", @"Rats", @"Good, I never read it anyway", nil); | |
134 } | |
135 | |
136 | |
137 /* Set the working directory to the .app's parent directory */ | |
138 - (void) setupWorkingDirectory:(BOOL)shouldChdir | |
139 { | |
140 if (shouldChdir) | |
141 { | |
142 char parentdir[MAXPATHLEN]; | |
143 CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); | |
144 CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url); | |
145 if (CFURLGetFileSystemRepresentation(url2, true, (UInt8 *)parentdir, MAXPATHLEN)) { | |
146 assert ( chdir (parentdir) == 0 ); /* chdir to the binary app's parent */ | |
147 } | |
148 CFRelease(url); | |
149 CFRelease(url2); | |
150 } | |
151 | |
152 } | |
153 | |
154 #if SDL_USE_NIB_FILE | |
155 | |
156 /* Fix menu to contain the real app name instead of "SDL App" */ | |
157 - (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName | |
158 { | |
159 NSRange aRange; | |
160 NSEnumerator *enumerator; | |
161 NSMenuItem *menuItem; | |
162 | |
163 aRange = [[aMenu title] rangeOfString:@"SDL App"]; | |
164 if (aRange.length != 0) | |
165 [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]]; | |
166 | |
167 enumerator = [[aMenu itemArray] objectEnumerator]; | |
168 while ((menuItem = [enumerator nextObject])) | |
169 { | |
170 aRange = [[menuItem title] rangeOfString:@"SDL App"]; | |
171 if (aRange.length != 0) | |
172 [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]]; | |
173 if ([menuItem hasSubmenu]) | |
174 [self fixMenu:[menuItem submenu] withAppName:appName]; | |
175 } | |
176 [ aMenu sizeToFit ]; | |
177 } | |
178 | |
179 #else | |
180 | |
181 static void setApplicationMenu(void) | |
182 { | |
183 /* warning: this code is very odd */ | |
184 NSMenu *appleMenu; | |
185 NSMenuItem *menuItem; | |
186 NSString *title; | |
187 NSString *appName; | |
188 | |
189 appName = getApplicationName(); | |
190 appleMenu = [[NSMenu alloc] initWithTitle:@""]; | |
191 | |
192 /* Add menu items */ | |
193 title = [@"About " stringByAppendingString:appName]; | |
194 [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; | |
195 | |
196 [appleMenu addItem:[NSMenuItem separatorItem]]; | |
197 | |
198 title = [@"Hide " stringByAppendingString:appName]; | |
199 [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; | |
200 | |
201 menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; | |
202 [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; | |
203 | |
204 [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; | |
205 | |
206 [appleMenu addItem:[NSMenuItem separatorItem]]; | |
207 | |
208 title = [@"Quit " stringByAppendingString:appName]; | |
209 [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; | |
210 | |
211 | |
212 /* Put menu into the menubar */ | |
213 menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; | |
214 [menuItem setSubmenu:appleMenu]; | |
215 [[NSApp mainMenu] addItem:menuItem]; | |
216 | |
217 /* Tell the application object that this is now the application menu */ | |
218 [NSApp setAppleMenu:appleMenu]; | |
219 | |
220 /* Finally give up our references to the objects */ | |
221 [appleMenu release]; | |
222 [menuItem release]; | |
223 } | |
224 | |
225 /* Create a window menu */ | |
226 static void setupWindowMenu(void) | |
227 { | |
228 NSMenu *windowMenu; | |
229 NSMenuItem *windowMenuItem; | |
230 NSMenuItem *menuItem; | |
231 | |
232 windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; | |
233 | |
234 /* "Minimize" item */ | |
235 menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; | |
236 [windowMenu addItem:menuItem]; | |
237 [menuItem release]; | |
238 | |
239 /* Put menu into the menubar */ | |
240 windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; | |
241 [windowMenuItem setSubmenu:windowMenu]; | |
242 [[NSApp mainMenu] addItem:windowMenuItem]; | |
243 | |
244 /* Tell the application object that this is now the window menu */ | |
245 [NSApp setWindowsMenu:windowMenu]; | |
246 | |
247 /* Finally give up our references to the objects */ | |
248 [windowMenu release]; | |
249 [windowMenuItem release]; | |
250 } | |
251 | |
252 /* Replacement for NSApplicationMain */ | |
253 static void CustomApplicationMain (int argc, char **argv) | |
254 { | |
255 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | |
256 SDLMain *sdlMain; | |
257 | |
258 /* Ensure the application object is initialised */ | |
259 [SDLApplication sharedApplication]; | |
260 | |
261 #ifdef SDL_USE_CPS | |
262 { | |
263 CPSProcessSerNum PSN; | |
264 /* Tell the dock about us */ | |
265 if (!CPSGetCurrentProcess(&PSN)) | |
266 if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) | |
267 if (!CPSSetFrontProcess(&PSN)) | |
268 [SDLApplication sharedApplication]; | |
269 } | |
270 #endif /* SDL_USE_CPS */ | |
271 | |
272 /* Set up the menubar */ | |
273 [NSApp setMainMenu:[[NSMenu alloc] init]]; | |
274 setApplicationMenu(); | |
275 setupWindowMenu(); | |
276 | |
277 /* Create SDLMain and make it the app delegate */ | |
278 sdlMain = [[SDLMain alloc] init]; | |
279 [NSApp setDelegate:sdlMain]; | |
280 | |
281 /* Start the main event loop */ | |
282 [NSApp run]; | |
283 | |
284 [sdlMain release]; | |
285 [pool release]; | |
286 } | |
287 | |
288 #endif | |
289 | |
290 | |
291 /* | |
292 * Catch document open requests...this lets us notice files when the app | |
293 * was launched by double-clicking a document, or when a document was | |
294 * dragged/dropped on the app's icon. You need to have a | |
295 * CFBundleDocumentsType section in your Info.plist to get this message, | |
296 * apparently. | |
297 * | |
298 * Files are added to gArgv, so to the app, they'll look like command line | |
299 * arguments. Previously, apps launched from the finder had nothing but | |
300 * an argv[0]. | |
301 * | |
302 * This message may be received multiple times to open several docs on launch. | |
303 * | |
304 * This message is ignored once the app's mainline has been called. | |
305 */ | |
306 - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename | |
307 { | |
308 const char *temparg; | |
309 size_t arglen; | |
310 char *arg; | |
311 char **newargv; | |
312 | |
313 if (!gFinderLaunch) /* MacOS is passing command line args. */ | |
314 return FALSE; | |
315 | |
316 if (gCalledAppMainline) /* app has started, ignore this document. */ | |
317 return FALSE; | |
318 | |
319 temparg = [filename UTF8String]; | |
320 arglen = SDL_strlen(temparg) + 1; | |
321 arg = (char *) SDL_malloc(arglen); | |
322 if (arg == NULL) | |
323 return FALSE; | |
324 | |
325 newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2)); | |
326 if (newargv == NULL) | |
327 { | |
328 SDL_free(arg); | |
329 return FALSE; | |
330 } | |
331 gArgv = newargv; | |
332 | |
333 SDL_strlcpy(arg, temparg, arglen); | |
334 gArgv[gArgc++] = arg; | |
335 gArgv[gArgc] = NULL; | |
336 return TRUE; | |
337 } | |
338 | |
339 | |
340 /* Called when the internal event loop has just started running */ | |
341 - (void) applicationDidFinishLaunching: (NSNotification *) note | |
342 { | |
343 int status; | |
344 | |
345 /* Set the working directory to the .app's parent directory */ | |
346 [self setupWorkingDirectory:gFinderLaunch]; | |
347 | |
348 #if SDL_USE_NIB_FILE | |
349 /* Set the main menu to contain the real app name instead of "SDL App" */ | |
350 [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()]; | |
351 #endif | |
352 | |
353 /* Hand off to main application code */ | |
354 gCalledAppMainline = TRUE; | |
355 status = SDL_main (gArgc, gArgv); | |
356 | |
357 /* We're done, thank you for playing */ | |
358 exit(status); | |
359 } | |
360 @end | |
361 | |
362 | |
363 @implementation NSString (ReplaceSubString) | |
364 | |
365 - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString | |
366 { | |
367 unsigned int bufferSize; | |
368 unsigned int selfLen = [self length]; | |
369 unsigned int aStringLen = [aString length]; | |
370 unichar *buffer; | |
371 NSRange localRange; | |
372 NSString *result; | |
373 | |
374 bufferSize = selfLen + aStringLen - aRange.length; | |
375 buffer = NSAllocateMemoryPages(bufferSize*sizeof(unichar)); | |
376 | |
377 /* Get first part into buffer */ | |
378 localRange.location = 0; | |
379 localRange.length = aRange.location; | |
380 [self getCharacters:buffer range:localRange]; | |
381 | |
382 /* Get middle part into buffer */ | |
383 localRange.location = 0; | |
384 localRange.length = aStringLen; | |
385 [aString getCharacters:(buffer+aRange.location) range:localRange]; | |
386 | |
387 /* Get last part into buffer */ | |
388 localRange.location = aRange.location + aRange.length; | |
389 localRange.length = selfLen - localRange.location; | |
390 [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange]; | |
391 | |
392 /* Build output string */ | |
393 result = [NSString stringWithCharacters:buffer length:bufferSize]; | |
394 | |
395 NSDeallocateMemoryPages(buffer, bufferSize); | |
396 | |
397 return result; | |
398 } | |
399 | |
400 @end | |
401 | |
402 | |
403 | |
404 #ifdef main | |
405 # undef main | |
406 #endif | |
407 | |
408 | |
409 /* Main entry point to executable - should *not* be SDL_main! */ | |
410 int main (int argc, char **argv) | |
411 { | |
412 /* Copy the arguments into a global variable */ | |
413 /* This is passed if we are launched by double-clicking */ | |
414 if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) { | |
415 gArgv = (char **) SDL_malloc(sizeof (char *) * 2); | |
416 gArgv[0] = argv[0]; | |
417 gArgv[1] = NULL; | |
418 gArgc = 1; | |
419 gFinderLaunch = YES; | |
420 } else { | |
421 int i; | |
422 gArgc = argc; | |
423 gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1)); | |
424 for (i = 0; i <= argc; i++) | |
425 gArgv[i] = argv[i]; | |
426 gFinderLaunch = NO; | |
427 } | |
428 | |
429 #if SDL_USE_NIB_FILE | |
430 [SDLApplication poseAsClass:[NSApplication class]]; | |
431 NSApplicationMain (argc, argv); | |
432 #else | |
433 CustomApplicationMain (argc, argv); | |
434 #endif | |
435 return 0; | |
436 } |