Subversion Repositories eduke32

Rev

Rev 4644 | Details | Compare with Previous | Last modification | View Log | RSS feed

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