root/OpenSceneGraph/trunk/examples/osgviewerSDL/SDLMainForMacOSX.m @ 6941

Revision 6941, 12.1 kB (checked in by robert, 8 years ago)

From Martin Lavery and Robert Osfield, Updated examples to use a variation of the MIT License

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* OpenSceneGraph example, osgviewerSDL.
2*
3*  Permission is hereby granted, free of charge, to any person obtaining a copy
4*  of this software and associated documentation files (the "Software"), to deal
5*  in the Software without restriction, including without limitation the rights
6*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7*  copies of the Software, and to permit persons to whom the Software is
8*  furnished to do so, subject to the following conditions:
9*
10*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16*  THE SOFTWARE.
17*/
18
19/*   SDLMain.m - main entry point for our Cocoa-ized SDL app
20       Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
21       Non-NIB-Code & other changes: Max Horn <max@quendi.de>
22
23    Feel free to customize this file to suit your needs
24       
25        OSG users: This is the standard SDLMain (nibless) that
26        comes with the SDL distribution. Only the file name has
27        been changed to avoid confusing non-Mac users.
28*/
29
30#import "SDL.h"
31#import "SDLMainForMacOSX.h"
32#import <sys/param.h> /* for MAXPATHLEN */
33#import <unistd.h>
34
35/* For some reaon, Apple removed setAppleMenu from the headers in 10.4,
36 but the method still is there and works. To avoid warnings, we declare
37 it ourselves here. */
38@interface NSApplication(SDL_Missing_Methods)
39- (void)setAppleMenu:(NSMenu *)menu;
40@end
41
42/* Use this flag to determine whether we use SDLMain.nib or not */
43#define         SDL_USE_NIB_FILE        0
44
45/* Use this flag to determine whether we use CPS (docking) or not */
46#define         SDL_USE_CPS             1
47#ifdef SDL_USE_CPS
48/* Portions of CPS.h */
49typedef struct CPSProcessSerNum
50{
51        UInt32          lo;
52        UInt32          hi;
53} CPSProcessSerNum;
54
55extern OSErr    CPSGetCurrentProcess( CPSProcessSerNum *psn);
56extern OSErr    CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
57extern OSErr    CPSSetFrontProcess( CPSProcessSerNum *psn);
58
59#endif /* SDL_USE_CPS */
60
61static int    gArgc;
62static char  **gArgv;
63static BOOL   gFinderLaunch;
64static BOOL   gCalledAppMainline = FALSE;
65
66static NSString *getApplicationName(void)
67{
68    NSDictionary *dict;
69    NSString *appName = 0;
70
71    /* Determine the application name */
72    dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
73    if (dict)
74        appName = [dict objectForKey: @"CFBundleName"];
75   
76    if (![appName length])
77        appName = [[NSProcessInfo processInfo] processName];
78
79    return appName;
80}
81
82#if SDL_USE_NIB_FILE
83/* A helper category for NSString */
84@interface NSString (ReplaceSubString)
85- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString;
86@end
87#endif
88
89@interface SDLApplication : NSApplication
90@end
91
92@implementation SDLApplication
93/* Invoked from the Quit menu item */
94- (void)terminate:(id)sender
95{
96    /* Post a SDL_QUIT event */
97    SDL_Event event;
98    event.type = SDL_QUIT;
99    SDL_PushEvent(&event);
100}
101@end
102
103/* The main class of the application, the application's delegate */
104@implementation SDLMain
105
106/* Set the working directory to the .app's parent directory */
107- (void) setupWorkingDirectory:(BOOL)shouldChdir
108{
109    if (shouldChdir)
110    {
111        char parentdir[MAXPATHLEN];
112                CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
113                CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url);
114                if (CFURLGetFileSystemRepresentation(url2, true, (UInt8 *)parentdir, MAXPATHLEN)) {
115                assert ( chdir (parentdir) == 0 );   /* chdir to the binary app's parent */
116                }
117                CFRelease(url);
118                CFRelease(url2);
119        }
120
121}
122
123#if SDL_USE_NIB_FILE
124
125/* Fix menu to contain the real app name instead of "SDL App" */
126- (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName
127{
128    NSRange aRange;
129    NSEnumerator *enumerator;
130    NSMenuItem *menuItem;
131
132    aRange = [[aMenu title] rangeOfString:@"SDL App"];
133    if (aRange.length != 0)
134        [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]];
135
136    enumerator = [[aMenu itemArray] objectEnumerator];
137    while ((menuItem = [enumerator nextObject]))
138    {
139        aRange = [[menuItem title] rangeOfString:@"SDL App"];
140        if (aRange.length != 0)
141            [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]];
142        if ([menuItem hasSubmenu])
143            [self fixMenu:[menuItem submenu] withAppName:appName];
144    }
145    [ aMenu sizeToFit ];
146}
147
148#else
149
150static void setApplicationMenu(void)
151{
152    /* warning: this code is very odd */
153    NSMenu *appleMenu;
154    NSMenuItem *menuItem;
155    NSString *title;
156    NSString *appName;
157   
158    appName = getApplicationName();
159    appleMenu = [[NSMenu alloc] initWithTitle:@""];
160   
161    /* Add menu items */
162    title = [@"About " stringByAppendingString:appName];
163    [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
164
165    [appleMenu addItem:[NSMenuItem separatorItem]];
166
167    title = [@"Hide " stringByAppendingString:appName];
168    [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
169
170    menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
171    [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
172
173    [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
174
175    [appleMenu addItem:[NSMenuItem separatorItem]];
176
177    title = [@"Quit " stringByAppendingString:appName];
178    [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
179
180   
181    /* Put menu into the menubar */
182    menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
183    [menuItem setSubmenu:appleMenu];
184    [[NSApp mainMenu] addItem:menuItem];
185
186    /* Tell the application object that this is now the application menu */
187    [NSApp setAppleMenu:appleMenu];
188
189    /* Finally give up our references to the objects */
190    [appleMenu release];
191    [menuItem release];
192}
193
194/* Create a window menu */
195static void setupWindowMenu(void)
196{
197    NSMenu      *windowMenu;
198    NSMenuItem  *windowMenuItem;
199    NSMenuItem  *menuItem;
200
201    windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
202   
203    /* "Minimize" item */
204    menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
205    [windowMenu addItem:menuItem];
206    [menuItem release];
207   
208    /* Put menu into the menubar */
209    windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
210    [windowMenuItem setSubmenu:windowMenu];
211    [[NSApp mainMenu] addItem:windowMenuItem];
212   
213    /* Tell the application object that this is now the window menu */
214    [NSApp setWindowsMenu:windowMenu];
215
216    /* Finally give up our references to the objects */
217    [windowMenu release];
218    [windowMenuItem release];
219}
220
221/* Replacement for NSApplicationMain */
222static void CustomApplicationMain (int argc, char **argv)
223{
224    NSAutoreleasePool   *pool = [[NSAutoreleasePool alloc] init];
225    SDLMain                             *sdlMain;
226
227    /* Ensure the application object is initialised */
228    [SDLApplication sharedApplication];
229   
230#ifdef SDL_USE_CPS
231    {
232        CPSProcessSerNum PSN;
233        /* Tell the dock about us */
234        if (!CPSGetCurrentProcess(&PSN))
235            if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
236                if (!CPSSetFrontProcess(&PSN))
237                    [SDLApplication sharedApplication];
238    }
239#endif /* SDL_USE_CPS */
240
241    /* Set up the menubar */
242    [NSApp setMainMenu:[[NSMenu alloc] init]];
243    setApplicationMenu();
244    setupWindowMenu();
245
246    /* Create SDLMain and make it the app delegate */
247    sdlMain = [[SDLMain alloc] init];
248    [NSApp setDelegate:sdlMain];
249   
250    /* Start the main event loop */
251    [NSApp run];
252   
253    [sdlMain release];
254    [pool release];
255}
256
257#endif
258
259
260/*
261 * Catch document open requests...this lets us notice files when the app
262 *  was launched by double-clicking a document, or when a document was
263 *  dragged/dropped on the app's icon. You need to have a
264 *  CFBundleDocumentsType section in your Info.plist to get this message,
265 *  apparently.
266 *
267 * Files are added to gArgv, so to the app, they'll look like command line
268 *  arguments. Previously, apps launched from the finder had nothing but
269 *  an argv[0].
270 *
271 * This message may be received multiple times to open several docs on launch.
272 *
273 * This message is ignored once the app's mainline has been called.
274 */
275- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
276{
277    const char *temparg;
278    size_t arglen;
279    char *arg;
280    char **newargv;
281
282    if (!gFinderLaunch)  /* MacOS is passing command line args. */
283        return FALSE;
284
285    if (gCalledAppMainline)  /* app has started, ignore this document. */
286        return FALSE;
287
288    temparg = [filename UTF8String];
289    arglen = SDL_strlen(temparg) + 1;
290    arg = (char *) SDL_malloc(arglen);
291    if (arg == NULL)
292        return FALSE;
293
294    newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2));
295    if (newargv == NULL)
296    {
297        SDL_free(arg);
298        return FALSE;
299    }
300    gArgv = newargv;
301
302    SDL_strlcpy(arg, temparg, arglen);
303    gArgv[gArgc++] = arg;
304    gArgv[gArgc] = NULL;
305    return TRUE;
306}
307
308
309/* Called when the internal event loop has just started running */
310- (void) applicationDidFinishLaunching: (NSNotification *) note
311{
312    int status;
313
314    /* Set the working directory to the .app's parent directory */
315    [self setupWorkingDirectory:gFinderLaunch];
316
317#if SDL_USE_NIB_FILE
318    /* Set the main menu to contain the real app name instead of "SDL App" */
319    [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()];
320#endif
321
322    /* Hand off to main application code */
323    gCalledAppMainline = TRUE;
324    status = SDL_main (gArgc, gArgv);
325
326    /* We're done, thank you for playing */
327    exit(status);
328}
329@end
330
331
332@implementation NSString (ReplaceSubString)
333
334- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString
335{
336    unsigned int bufferSize;
337    unsigned int selfLen = [self length];
338    unsigned int aStringLen = [aString length];
339    unichar *buffer;
340    NSRange localRange;
341    NSString *result;
342
343    bufferSize = selfLen + aStringLen - aRange.length;
344    buffer = NSAllocateMemoryPages(bufferSize*sizeof(unichar));
345   
346    /* Get first part into buffer */
347    localRange.location = 0;
348    localRange.length = aRange.location;
349    [self getCharacters:buffer range:localRange];
350   
351    /* Get middle part into buffer */
352    localRange.location = 0;
353    localRange.length = aStringLen;
354    [aString getCharacters:(buffer+aRange.location) range:localRange];
355     
356    /* Get last part into buffer */
357    localRange.location = aRange.location + aRange.length;
358    localRange.length = selfLen - localRange.location;
359    [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange];
360   
361    /* Build output string */
362    result = [NSString stringWithCharacters:buffer length:bufferSize];
363   
364    NSDeallocateMemoryPages(buffer, bufferSize);
365   
366    return result;
367}
368
369@end
370
371
372
373#ifdef main
374undef main
375#endif
376
377
378/* Main entry point to executable - should *not* be SDL_main! */
379int main (int argc, char **argv)
380{
381    /* Copy the arguments into a global variable */
382    /* This is passed if we are launched by double-clicking */
383    if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) {
384        gArgv = (char **) SDL_malloc(sizeof (char *) * 2);
385        gArgv[0] = argv[0];
386        gArgv[1] = NULL;
387        gArgc = 1;
388        gFinderLaunch = YES;
389    } else {
390        int i;
391        gArgc = argc;
392        gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1));
393        for (i = 0; i <= argc; i++)
394            gArgv[i] = argv[i];
395        gFinderLaunch = NO;
396    }
397
398#if SDL_USE_NIB_FILE
399    [SDLApplication poseAsClass:[NSApplication class]];
400    NSApplicationMain (argc, argv);
401#else
402    CustomApplicationMain (argc, argv);
403#endif
404    return 0;
405}
Note: See TracBrowser for help on using the browser.