~ubuntu-branches/debian/sid/ember/sid

« back to all changes in this revision

Viewing changes to src/main/macosx/SDLMain.m

  • Committer: Bazaar Package Importer
  • Author(s): Michael Koch
  • Date: 2009-07-23 07:46:40 UTC
  • Revision ID: james.westby@ubuntu.com-20090723074640-wh0ukzis0kda36qv
Tags: upstream-0.5.6
ImportĀ upstreamĀ versionĀ 0.5.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}
 
384