Subversion Repositories eduke32

Rev

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