Subversion Repositories eduke32

Rev

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