Mercurial > sdl-ios-xcode
comparison Xcode/TemplatesForXcode/SDL 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 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 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 /* 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, true, (UInt8 *)parentdir, MAXPATHLEN)) { | |
93 assert ( chdir (parentdir) == 0 ); /* chdir to the binary app's parent */ | |
94 } | |
95 CFRelease(url); | |
96 CFRelease(url2); | |
97 } | |
98 | |
99 } | |
100 | |
101 #if SDL_USE_NIB_FILE | |
102 | |
103 /* Fix menu to contain the real app name instead of "SDL App" */ | |
104 - (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName | |
105 { | |
106 NSRange aRange; | |
107 NSEnumerator *enumerator; | |
108 NSMenuItem *menuItem; | |
109 | |
110 aRange = [[aMenu title] rangeOfString:@"SDL App"]; | |
111 if (aRange.length != 0) | |
112 [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]]; | |
113 | |
114 enumerator = [[aMenu itemArray] objectEnumerator]; | |
115 while ((menuItem = [enumerator nextObject])) | |
116 { | |
117 aRange = [[menuItem title] rangeOfString:@"SDL App"]; | |
118 if (aRange.length != 0) | |
119 [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]]; | |
120 if ([menuItem hasSubmenu]) | |
121 [self fixMenu:[menuItem submenu] withAppName:appName]; | |
122 } | |
123 [ aMenu sizeToFit ]; | |
124 } | |
125 | |
126 #else | |
127 | |
128 static void setApplicationMenu(void) | |
129 { | |
130 /* warning: this code is very odd */ | |
131 NSMenu *appleMenu; | |
132 NSMenuItem *menuItem; | |
133 NSString *title; | |
134 NSString *appName; | |
135 | |
136 appName = getApplicationName(); | |
137 appleMenu = [[NSMenu alloc] initWithTitle:@""]; | |
138 | |
139 /* Add menu items */ | |
140 title = [@"About " stringByAppendingString:appName]; | |
141 [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; | |
142 | |
143 [appleMenu addItem:[NSMenuItem separatorItem]]; | |
144 | |
145 title = [@"Hide " stringByAppendingString:appName]; | |
146 [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; | |
147 | |
148 menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; | |
149 [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; | |
150 | |
151 [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; | |
152 | |
153 [appleMenu addItem:[NSMenuItem separatorItem]]; | |
154 | |
155 title = [@"Quit " stringByAppendingString:appName]; | |
156 [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; | |
157 | |
158 | |
159 /* Put menu into the menubar */ | |
160 menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; | |
161 [menuItem setSubmenu:appleMenu]; | |
162 [[NSApp mainMenu] addItem:menuItem]; | |
163 | |
164 /* Tell the application object that this is now the application menu */ | |
165 [NSApp setAppleMenu:appleMenu]; | |
166 | |
167 /* Finally give up our references to the objects */ | |
168 [appleMenu release]; | |
169 [menuItem release]; | |
170 } | |
171 | |
172 /* Create a window menu */ | |
173 static void setupWindowMenu(void) | |
174 { | |
175 NSMenu *windowMenu; | |
176 NSMenuItem *windowMenuItem; | |
177 NSMenuItem *menuItem; | |
178 | |
179 windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; | |
180 | |
181 /* "Minimize" item */ | |
182 menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; | |
183 [windowMenu addItem:menuItem]; | |
184 [menuItem release]; | |
185 | |
186 /* Put menu into the menubar */ | |
187 windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; | |
188 [windowMenuItem setSubmenu:windowMenu]; | |
189 [[NSApp mainMenu] addItem:windowMenuItem]; | |
190 | |
191 /* Tell the application object that this is now the window menu */ | |
192 [NSApp setWindowsMenu:windowMenu]; | |
193 | |
194 /* Finally give up our references to the objects */ | |
195 [windowMenu release]; | |
196 [windowMenuItem release]; | |
197 } | |
198 | |
199 /* Replacement for NSApplicationMain */ | |
200 static void CustomApplicationMain (int argc, char **argv) | |
201 { | |
202 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | |
203 SDLMain *sdlMain; | |
204 | |
205 /* Ensure the application object is initialised */ | |
206 [SDLApplication sharedApplication]; | |
207 | |
208 #ifdef SDL_USE_CPS | |
209 { | |
210 CPSProcessSerNum PSN; | |
211 /* Tell the dock about us */ | |
212 if (!CPSGetCurrentProcess(&PSN)) | |
213 if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) | |
214 if (!CPSSetFrontProcess(&PSN)) | |
215 [SDLApplication sharedApplication]; | |
216 } | |
217 #endif /* SDL_USE_CPS */ | |
218 | |
219 /* Set up the menubar */ | |
220 [NSApp setMainMenu:[[NSMenu alloc] init]]; | |
221 setApplicationMenu(); | |
222 setupWindowMenu(); | |
223 | |
224 /* Create SDLMain and make it the app delegate */ | |
225 sdlMain = [[SDLMain alloc] init]; | |
226 [NSApp setDelegate:sdlMain]; | |
227 | |
228 /* Start the main event loop */ | |
229 [NSApp run]; | |
230 | |
231 [sdlMain release]; | |
232 [pool release]; | |
233 } | |
234 | |
235 #endif | |
236 | |
237 | |
238 /* | |
239 * Catch document open requests...this lets us notice files when the app | |
240 * was launched by double-clicking a document, or when a document was | |
241 * dragged/dropped on the app's icon. You need to have a | |
242 * CFBundleDocumentsType section in your Info.plist to get this message, | |
243 * apparently. | |
244 * | |
245 * Files are added to gArgv, so to the app, they'll look like command line | |
246 * arguments. Previously, apps launched from the finder had nothing but | |
247 * an argv[0]. | |
248 * | |
249 * This message may be received multiple times to open several docs on launch. | |
250 * | |
251 * This message is ignored once the app's mainline has been called. | |
252 */ | |
253 - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename | |
254 { | |
255 const char *temparg; | |
256 size_t arglen; | |
257 char *arg; | |
258 char **newargv; | |
259 | |
260 if (!gFinderLaunch) /* MacOS is passing command line args. */ | |
261 return FALSE; | |
262 | |
263 if (gCalledAppMainline) /* app has started, ignore this document. */ | |
264 return FALSE; | |
265 | |
266 temparg = [filename UTF8String]; | |
267 arglen = SDL_strlen(temparg) + 1; | |
268 arg = (char *) SDL_malloc(arglen); | |
269 if (arg == NULL) | |
270 return FALSE; | |
271 | |
272 newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2)); | |
273 if (newargv == NULL) | |
274 { | |
275 SDL_free(arg); | |
276 return FALSE; | |
277 } | |
278 gArgv = newargv; | |
279 | |
280 SDL_strlcpy(arg, temparg, arglen); | |
281 gArgv[gArgc++] = arg; | |
282 gArgv[gArgc] = NULL; | |
283 return TRUE; | |
284 } | |
285 | |
286 | |
287 /* Called when the internal event loop has just started running */ | |
288 - (void) applicationDidFinishLaunching: (NSNotification *) note | |
289 { | |
290 int status; | |
291 | |
292 /* Set the working directory to the .app's parent directory */ | |
293 [self setupWorkingDirectory:gFinderLaunch]; | |
294 | |
295 #if SDL_USE_NIB_FILE | |
296 /* Set the main menu to contain the real app name instead of "SDL App" */ | |
297 [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()]; | |
298 #endif | |
299 | |
300 /* Hand off to main application code */ | |
301 gCalledAppMainline = TRUE; | |
302 status = SDL_main (gArgc, gArgv); | |
303 | |
304 /* We're done, thank you for playing */ | |
305 exit(status); | |
306 } | |
307 @end | |
308 | |
309 | |
310 @implementation NSString (ReplaceSubString) | |
311 | |
312 - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString | |
313 { | |
314 unsigned int bufferSize; | |
315 unsigned int selfLen = [self length]; | |
316 unsigned int aStringLen = [aString length]; | |
317 unichar *buffer; | |
318 NSRange localRange; | |
319 NSString *result; | |
320 | |
321 bufferSize = selfLen + aStringLen - aRange.length; | |
322 buffer = NSAllocateMemoryPages(bufferSize*sizeof(unichar)); | |
323 | |
324 /* Get first part into buffer */ | |
325 localRange.location = 0; | |
326 localRange.length = aRange.location; | |
327 [self getCharacters:buffer range:localRange]; | |
328 | |
329 /* Get middle part into buffer */ | |
330 localRange.location = 0; | |
331 localRange.length = aStringLen; | |
332 [aString getCharacters:(buffer+aRange.location) range:localRange]; | |
333 | |
334 /* Get last part into buffer */ | |
335 localRange.location = aRange.location + aRange.length; | |
336 localRange.length = selfLen - localRange.location; | |
337 [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange]; | |
338 | |
339 /* Build output string */ | |
340 result = [NSString stringWithCharacters:buffer length:bufferSize]; | |
341 | |
342 NSDeallocateMemoryPages(buffer, bufferSize); | |
343 | |
344 return result; | |
345 } | |
346 | |
347 @end | |
348 | |
349 | |
350 | |
351 #ifdef main | |
352 # undef main | |
353 #endif | |
354 | |
355 | |
356 /* Main entry point to executable - should *not* be SDL_main! */ | |
357 int main (int argc, char **argv) | |
358 { | |
359 /* Copy the arguments into a global variable */ | |
360 /* This is passed if we are launched by double-clicking */ | |
361 if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) { | |
362 gArgv = (char **) SDL_malloc(sizeof (char *) * 2); | |
363 gArgv[0] = argv[0]; | |
364 gArgv[1] = NULL; | |
365 gArgc = 1; | |
366 gFinderLaunch = YES; | |
367 } else { | |
368 int i; | |
369 gArgc = argc; | |
370 gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1)); | |
371 for (i = 0; i <= argc; i++) | |
372 gArgv[i] = argv[i]; | |
373 gFinderLaunch = NO; | |
374 } | |
375 | |
376 #if SDL_USE_NIB_FILE | |
377 [SDLApplication poseAsClass:[NSApplication class]]; | |
378 NSApplicationMain (argc, argv); | |
379 #else | |
380 CustomApplicationMain (argc, argv); | |
381 #endif | |
382 return 0; | |
383 } |