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